2016年4月1日更新:
推薦一個產品質量跟蹤系統:網易雲捕,完全免費,個人和企業均可使用。
雲捕是網易旗下的質量跟蹤平台 , 積淀網易多年來質量跟蹤技術經驗, 面向移動開發者提供專業的 Crash 監控、崩潰分析等質量跟蹤服務。開發者通過雲捕官網(crash.163.com ) ,即可快速接入服務。雲捕能夠實時監控異常,准確定位崩潰堆棧信息,可定制個性化的實時告警功能以及直觀的報表統計, 幫助移動互聯網開發者 及時掌控產品異常,全面了解質量問題,快速修復解決,打造良好的用戶體驗。
功能范圍
實時監控: 實時上報 Crash 信息,全面監控相關異常情況
趨勢分析: 根據 Crash 次數,形成相關趨勢圖,及時了解 Crash 動態
Crash分布: 提供全面完整的機器運行信息,全方位定位 Crash 信息
崩潰堆棧: 詳細顯示崩潰堆棧信息,直接定位出錯代碼行號
服務優勢
品牌保障: 作為網易內部一直在使用的產品,雲捕積累了多年的質量跟蹤技術經驗。
全面平台支持: 支持Android與iOS兩大移動平台 , 完美支持各種開發環境
實時准確: 實時上報Crash信息,准確定位崩潰堆棧信息,實現高效質量跟蹤
個性化定制: 提供自定義告警設置,幫助開發者快速響應崩潰數量異常情況
2015年12月14日更新:
這些內容均是在AndroidStudio出現之前整理總結的,那時候eclipse的ADT bundle盛行,只有intelij IDEA帶的插件開發Android應用程序,但是個人不喜歡用eclipse,所以盡管帶插件的intelij IDEA有很多蹩腳和不足之處,依然覺得比eclipse好過百倍(個人喜好,不喜勿噴),還是堅持用了下來,現在的AndroidStudio版本比之前強百倍,但是NDK這塊的支持依然不敢苟同,畢竟是超越不了VS,所以也在那個時候獨創了VS編譯NDK的方法(其實也是奇技淫巧啦~),編程效率也是極高的,下面的篇幅如果看不懂可以不用再看,直接點傳送門
《Windows下Android NDK開發的幾種方法總結》參考第三個方法“三、結合方法一和方法二,配合使用vs2005和ndk-build.cmd”即可。
以下是原文
參考資料:
【android ndk】macos環境下Android Studio中利用gradle編譯jni模塊及配置:
http://demo.netfoucs.com/ashqal/article/details/21869151
ANDROID STUDIO, GRADLE AND NDK INTEGRATION:
http://ph0b.com/android-studio-gradle-and-ndk-integration/
Gradle Plugin User Guide:
http://tools.android.com/tech-docs/new-build-system/user-guide
New Build System:
http://tools.android.com/tech-docs/new-build-system
實踐證明:
0.4.2只有在gradle1.10版本下創建只包含AndroidLibrary模塊的工程時才能正常編譯,gradle1.9版本不可以。
0.4.6使用gradle1.10可以。
0.5.0無論是gradle1.10還是gradle1.11版本都可以生成so庫。
0.5.5的不能編譯NDK,無論是gradle1.10還是gradle1.11版本都不能生成so庫,屙血尿膿。
下載AndroidStudio:
AndroidStudio的歷史版本下載列表:
http://tools.android.com/download/studio/canary
下載NDK:
下載鏈接:
http://developer.android.com/tools/sdk/ndk/index.html,注意NDK一定要r9+版本的,否則編譯時會出現如下
錯誤:
Execution failed for task ':hellojni:compileDebugNdk'.
> com.android.ide.common.internal.LoggedErrorException: Failed to run command:
D:\ndk\ndk-build.cmd NDK_PROJECT_PATH=null APP_BUILD_SCRIPT=F:\androidstudio\test\hellojni\build\ndk\debug\Android.mk APP_PLATFORM=android-19 NDK_OUT=F:\androidstudio\test\hellojni\build\ndk\debug\obj NDK_LIBS_OUT=F:\androidstudio\test\hellojni\build\ndk\debug\lib APP_ABI=armeabi,armeabi-v7a
Error Code:
2
Output:
D:/ndk/build/core/setup-app.mk:63: *** Android NDK: Aborting . Stop.
下載gradle:
gradle-1.9-all.zip:
http://download.csdn.net/detail/xxhongdev/6834859
gradle-1.10-all.zip:
http://download.csdn.net/detail/xinghuacheng/7026815
gradle-1.11-all.zip:
http://download.csdn.net/detail/d1387968/7097249
通過“AndroidStudio歷史版本下載列表”下載的歷史版本通常是綠色的壓縮包,可以直接解壓縮使用,但是不包含SDK,需要額外下載SDK,由於之前下載了ADT(版本:adt20131030),所以后面直接使用ADT目錄下的SDK。通過
http://developer.android.com/sdk/installing/studio.html首頁下載的AndroidStudio為安裝版本,包含了SDK,可以下載后直接安裝,首次使用創建項目會比較慢,可以參考“
AndroidStudio創建項目時一直處於building“project name”gradle project info的解決辦法”來解決。
創建項目:
運行AndroidStudio后,創建新項目,新項目會有一個默認的Module,這里項目名稱為JNIDemo,Module為app。
然后通過向導完成項目的創建。
AndroidStudio還是非常慢的,長時間處於這種狀態:
經過漫長的等待后終於完成項目的創建,然后在這個項目下創建一個Module,New Module->Android Library:
不勾選“Create activity”然后點擊“Finish”完成創建,此時項目結構如圖:
app和hellojni均為JNIDemo下的兩個Module,這里把hellojni作為生成so庫的NDK開發層,把app作為調用so庫的APK引用開發層。
在hellojni模塊的src/main下創建jni目錄,並在jni目錄下新建文件main.cpp,代碼如下:
#include <stdio.h>
#include <stdlib.h>
#include <jni.h>
#include <assert.h>
#include <sys/types.h>
#include <android/log.h>
#define LOG_TAG "Hellojni"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
//注冊native api的類#define JNIREG_CLASS "com/example/test9/app/MainActivity"
extern "C" {
JNIEXPORT void msg(JNIEnv *env, jobject clazz, jstring str);
};
//jstring to char* char* jstringTostring(JNIEnv* env, jstring jstr)
{
char* rtn = NULL;
jclass clsstring = env->FindClass("java/lang/String");
jstring strencode = env->NewStringUTF("utf-8");
jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
jsize alen = env->GetArrayLength(barr);
jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
if (alen > 0)
{
rtn = (char*)malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
env->ReleaseByteArrayElements(barr, ba, 0);
return rtn;
}
JNIEXPORT void msg(JNIEnv *env, jobject clazz, jstring str)
{
char *pszstr = NULL;
pszstr = jstringTostring(env, str);
LOGI("%s", pszstr);
free(pszstr);
}
/**
* Table of methods associated with a single class.
*/static JNINativeMethod gMethods[] = {
{ "msg", "(Ljava/lang/String;)V", (void*)msg},
};
/*
* Register native methods for all classes we know about.
*/static int registerNativeMethods(JNIEnv* env)
{
int nError = 0;
jclass clazz = NULL;
clazz = env->FindClass(JNIREG_CLASS);
if (clazz == NULL) {
LOGE("clazz is null");
return JNI_FALSE;
}
nError = env->RegisterNatives(clazz, gMethods, sizeof(gMethods) / sizeof(gMethods[0]) );
if ( nError < 0 ) {
LOGE("RegisterNatives error: %d num: %d",nError, sizeof(gMethods) / sizeof(gMethods[0]) );
return JNI_FALSE;
}
return JNI_TRUE;
}
/*
* Set some test stuff up.
*
* Returns the JNI version on success, -1 on failure.
*/
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
JNIEnv* env = NULL;
jint result = -1;
if(vm->GetEnv((void**) &env,JNI_VERSION_1_6) != JNI_OK){
return -1;
}
assert(env != NULL);
if (!registerNativeMethods(env)) {
LOGE("registerNativeMethods failed");
return -1;
}
/* success -- return valid version number */
result = JNI_VERSION_1_6;
return result;
}
打開local.properties,設置正確的SDK路徑和NDK路徑:
sdk.dir=D\:/adt20131030/sdk ndk.dir=D\:/ndk
打開項目gradle/wrapper目錄下的gradle-wrapper.properties文件,修改:
#Wed Apr 10 15:27:10 PDT 2013 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=http\://services.gradle.org/distributions/gradle-1.9-all.zip
#Wed Apr 10 15:27:10 PDT 2013 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=http\://services.gradle.org/distributions/gradle-1.10-all.zip
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.7.+'
}
}
allprojects {
repositories {
mavenCentral()
}
}
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.9.+'
}
}
allprojects {
repositories {
mavenCentral()
}
}
0.7.0 Requires Gradle 1.9 Requires Studio 0.4.0
0.9.0 Compatible with Gradle 1.10 and 1.11 Using Gradle 1.11 requires Android Studio 0.5.0
另外還需要注意的是gradle1.9下沒有buildTypes標簽,需要將debug、release標簽直接放在android標簽內,在gradle1.10下debug、release需要放在buildTypes標簽內,buildTypes在android內。這里hellojni配置的build.gradle文件內容如下:
assert gradle.gradleVersion >= "1.10"
apply plugin: 'android-library'
android {
compileSdkVersion 19
buildToolsVersion "19.0.3"
defaultConfig {
minSdkVersion 8
targetSdkVersion 16
versionCode 1
versionName "1.0"
}
buildTypes {
release {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
ndk {
moduleName "hellojni"
abiFilters "armeabi", "armeabi-v7a", "x86"
}
}
debug {
ndk {
moduleName "hellojni"
//stl "stlport_shared"
ldLibs "log", "z", "m"
//cFlags "-Wall -Wextra -I " + projectDir + "/src/main/jni/include"
abiFilters "armeabi", "armeabi-v7a", "x86"
}
}
}
productFlavors {
x86 {
versionCode Integer.parseInt("6" + defaultConfig.versionCode)
ndk {
abiFilter "x86"
}
}
mips {
versionCode Integer.parseInt("4" + defaultConfig.versionCode)
ndk {
abiFilter "mips"
}
}
armv7 {
versionCode Integer.parseInt("2" + defaultConfig.versionCode)
ndk {
abiFilter "armeabi-v7a"
}
}
arm {
versionCode Integer.parseInt("1" + defaultConfig.versionCode)
ndk {
abiFilters "armeabi", "armeabi-v7a"
}
}
fat
}
}
dependencies {
compile 'com.android.support:appcompat-v7:19.+'
compile fileTree(dir: 'libs', include: ['*.jar'])
}
注意這里的Android.mk文件每次編譯都會重新由工具自動生成,而非手動編輯的,我覺得這一點設計就比較差勁。例如如果想要使用log輸出函數__android_log_print,需要添加“LOCAL_LDLIBS := -llog”,則在build.gradle文件中添加如下的配置:
debug {
ndk {
ldLibs "log"
}
}
右鍵工程選擇Open Module Settings,選擇Modules-app,打開Dependencies選項卡點擊“+”號,選擇Module dependency,在打開的對話框中選擇hellojni。
但是測試發現設置依賴沒有效果,如果直接編譯app,hellojni並沒有編譯,仍需要手動編譯hellojni。
調用native函數:
app項目中,在MainActivity類中聲明native函數:
public native void msg(String str);
static {
System.loadLibrary("hellojni");
}
在MainActivity::onCreate中調用native函數打印一句log:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
msg("MainActivity onCreate");
}
還需要將hellojni生成的so庫文件打包進apk,仍需要配置build.gradle文件,添加:
task copyNativeLibs(type: Copy) {
from fileTree(dir: '../hellojni/build/ndk/arm/debug/lib', include: 'armeabi/*.so') into 'build/lib'
}
tasks.withType(Compile) {
compileTask -> compileTask.dependsOn copyNativeLibs
}
clean.dependsOn 'cleanCopyNativeLibs'
tasks.withType(com.android.build.gradle.tasks.PackageApplication) { pkgTask ->
pkgTask.jniFolders = [new File(buildDir, 'lib')]
}
參考:“Android Studio添加so庫”
http://blog.csdn.net/caesardadi/article/details/18264399
其中copyNativeLibs任務是從相對app的項目路徑'../hellojni/build/ndk/arm/debug/lib'下復制所有armeabi子目錄的so文件到本項目build目錄下的lib目錄中,執行效果:
這樣最后打包生成的apk包才會包含有hellojni的so庫文件。
測試:
編譯運行app,apk安裝完畢運行時輸出log信息:
后面列出了可能出現的gradle錯誤以及解決方案,以供參考。
錯誤:
Execution failed for task ':hellojni:compileDebugNdk'.
> com.android.ide.common.internal.LoggedErrorException: Failed to run command:
D:\ndk\ndk-build.cmd NDK_PROJECT_PATH=null APP_BUILD_SCRIPT=F:\androidstudio\test\hellojni\build\ndk\debug\Android.mk APP_PLATFORM=android-19 NDK_OUT=F:\androidstudio\test\hellojni\build\ndk\debug\obj NDK_LIBS_OUT=F:\androidstudio\test\hellojni\build\ndk\debug\lib APP_ABI=armeabi,armeabi-v7a
Error Code:
2
Output:
make.exe: *** No rule to make target `F:\androidstudio\test\hellojni\build\ndk\debug\obj/local/armeabi/objs/jnimain/F_\androidstudio\test\hellojni\src\main\jni', needed by `F:\androidstudio\test\hellojni\build\ndk\debug\obj/local/armeabi/objs/jnimain/F_\androidstudio\test\hellojni\src\main\jni\hellojni.o'. Stop.
解決方案:
這是NDK在Windows下一個bug,當只編譯一個文件時出現,解決方法就是再添加一個空的文件即可。
This may come from a current NDK bug on Windows, when there is only one source file to compile. You only need to add one empty source to make it work again.
錯誤:
Could not determine the dependencies of task ':hellojni:compileArmDebugJava'. > failed to find Build Tools revision 19.0.3
解決方案:
這個Build Tools是指“Android SDK Build-tools”,打開SDK Manager勾選相應版本(例如這里是19.0.3)安裝即可。
錯誤:
FAILURE: Build failed with an exception. * What went wrong: Task 'assembleArmDebug' not found in project ':hellojni'. Some candidates are: 'assembleDebug'. * Try: Run gradle tasks to get a list of available tasks. Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
解決方案:
在
android { }中添加:
productFlavors{
arm {
}
}
productFlavors {
x86 {
versionCode Integer.parseInt("6" + defaultConfig.versionCode)
ndk {
abiFilter "x86"
}
}
mips {
versionCode Integer.parseInt("4" + defaultConfig.versionCode)
ndk {
abiFilter "mips"
}
}
armv7 {
versionCode Integer.parseInt("2" + defaultConfig.versionCode)
ndk {
abiFilter "armeabi-v7a"
}
}
arm {
versionCode Integer.parseInt("1" + defaultConfig.versionCode)
ndk {
abiFilter "armeabi"
//abiFilters "armeabi", "armeabi-v7a"
}
}
fat
}
錯誤:
Execution failed for task ':hellojni:compileDebugNdk'. > java.io.IOException: Cannot run program "D:\ndk\ndk-build": CreateProcess error=193, %1 ??????Ч?? Win32 ??ó
在使用gradle1.9版本時遇到,使用gradle1.10版本來解決。
錯誤:
A problem occurred evaluating project ':app'. > Could not create plugin of type 'AppPlugin'.
Don’t use latest Gradle (version 1.10), downgrade to 1.9。參考:
http://blog.vyvazil.eu/tag/android-studio/
但是如果我們使用gradle1.9版本的話又會出現
錯誤:
Execution failed for task ':hellojni:compileDebugNdk'. > java.io.IOException: Cannot run program "D:\ndk\ndk-build": CreateProcess error=193, %1 ??????Ч?? Win32 ??ó
無論使用哪個版本都有問題,后來仔細查看了下'AppPlugin'這個錯誤是出現在‘app’模塊上的而非‘hellojni’模塊上,於是考慮新建工程項目並且只在該工程下建立一個庫模塊,不再創建app模塊,如圖:
這里不勾選“Create custom launcher icon”和“Create activity”,直接finish完成,其他配置參考前述,最后編譯后可以生成so庫文件:
錯誤:
這個錯誤忘記記錄了囧
解決方案:
File-Settings-Gradle-Gradle VM options:-Xmx512m
