使用AndroidStudio編譯NDK的方法及錯誤解決方案

來源:互聯網
上載者:User

標籤:

參考資料:【android ndk】macos環境下Android Studio中利用gradle編譯jni模組及配置:http://demo.netfoucs.com/ashqal/article/details/21869151ANDROID 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-guideNew 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-v7aError Code:    2Output:    D:/ndk/build/core/setup-app.mk:63: *** Android NDK: Aborting    .  Stop.
下載gradle:gradle-1.9-all.zip:http://download.csdn.net/detail/xxhongdev/6834859gradle-1.10-all.zip:http://download.csdn.net/detail/xinghuacheng/7026815gradle-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;}
這裡只匯出一個msg函數列印傳遞進來的字串,僅作測試。再在jni目錄下建立一個empty.cpp檔案,內容為空白,這個是為瞭解決NDK的bug所作的,以防編譯出錯。 開啟local.properties,設定正確的SDK路徑和NDK路徑:
sdk.dir=D\:/adt20131030/sdkndk.dir=D\:/ndk
開啟項目gradle/wrapper目錄下的gradle-wrapper.properties檔案,修改:
#Wed Apr 10 15:27:10 PDT 2013distributionBase=GRADLE_USER_HOMEdistributionPath=wrapper/distszipStoreBase=GRADLE_USER_HOMEzipStorePath=wrapper/distsdistributionUrl=http\://services.gradle.org/distributions/gradle-1.9-all.zip
為:
#Wed Apr 10 15:27:10 PDT 2013distributionBase=GRADLE_USER_HOMEdistributionPath=wrapper/distszipStoreBase=GRADLE_USER_HOMEzipStorePath=wrapper/distsdistributionUrl=http\://services.gradle.org/distributions/gradle-1.10-all.zip
並開啟項目根目錄下的build.gradle檔案,修改:
// 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()    }}
為(指定使用gradle1.10則修改為0.9.+,指定使用gradle1.11則修改為0.9.2):
// 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()    }}
解釋:參考http://tools.android.com/tech-docs/new-build-system知道
0.7.0Requires Gradle 1.9Requires Studio 0.4.0
0.9.0Compatible with Gradle 1.10 and 1.11Using Gradle 1.11 requires Android Studio 0.5.0
如果配置的是0.7.+則預設使用gradle1.9,如果設定為0.9.+則預設使用gradle1.10。 另外還需要注意的是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‘])}
然後選擇hellojni項目右鍵“Make Module hellojni”,等待一段時間後會在項目下產生build-ndk目錄,目錄下會有一些不同版本的so庫檔案產生,注意這裡的Android.mk檔案每次編譯都會重新由工具自動產生,而非手動編輯的,我覺得這一點設計就比較差勁。例如如果想要使用log輸出函數__android_log_print,需要添加“LOCAL_LDLIBS :=  -llog”,則在build.gradle檔案中添加如下的配置:
        debug {            ndk {                ldLibs "log"            }        }
由gradle根據配置再去產生Android.mk檔案,最後再調用ndk進行編譯。  右鍵工程選擇Open Module Settings,選擇Modules-app,開啟Dependencies選項卡點擊“+”號,選擇Module dependency,在開啟的對話方塊中選擇hellojni。 但是測試發現設定依賴沒有效果,如果直接編譯app,hellojni並沒有編譯,仍需要手動編譯hellojni。   調用native函數: app項目中,在MainActivity類中聲明native函數:
public native void msg(String str);
並添加靜態代碼載入hellojni庫:
    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-v7aError Code:    2Output:    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,當只編譯一個檔案時出現,解決方案就是再添加一個空的檔案即可。原文見http://ph0b.com/android-studio-gradle-and-ndk-integration/:
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 

使用AndroidStudio編譯NDK的方法及錯誤解決方案

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.