1. 程式人生 > >[Android jni開發系列(二)]AndroidStudio移植eclipse NDK專案開發

[Android jni開發系列(二)]AndroidStudio移植eclipse NDK專案開發

1、在eclipse上開發ndk專案時一般都是在專案裡新建jni目錄,通過編寫Android.mk和Application.mk編譯生成so庫,然後放到libs目錄下就可以使用,下面來看下,在AndroidStudio怎麼採用這種方式生成so。

2、利用AndroidStudio配置幾個需要用到的快捷命令,javah、ndk-build、ndk-build clean,具體作用如下:

javah:根據java檔案生成對應的jni標頭檔案
這裡寫圖片描述

Program$JDKPath$\bin\javah.exe
Parameters:-classpath . -jni -d $ModuleFileDir
$\src\main\jni $FileClass$ Working directory:$ModuleFileDir$\src\main\java

ndk-build:ndk編譯生成so
這裡寫圖片描述

\\ndk路徑
Program:D:\adt-bundle-windows-x86_64-20140702\android-ndk-r15c\ndk-build.cmd  
Parameters:
Working directory:$ProjectFileDir$\app\src\main\

ndk-build clean:清除ndk編譯環境
這裡寫圖片描述

\\ndk路徑
Program:D:\adt
-bundle-windows-x86_64-20140702\android-ndk-r15c\ndk-build.cmd Parameters:clean Working directory:$ProjectFileDir$\app\src\main\

3、快捷命令配置好後,就可以開始了,選中需要生成jni標頭檔案的java類,右鍵——>External Tool——>javah
這裡寫圖片描述
會自動新建jni目錄,並生成對應的jni標頭檔案

    public class NdkTest {
        static {
            System.loadLibrary("test_ndk"
); } public native String getString(); }

通過上面方式生成的標頭檔案“com_jason_jni_demo2_NdkTest.h”

/* DO NOT EDIT THIS FILE - it is machine generated */
    #include <jni.h>
    /* Header for class com_jason_jni_demo2_NdkTest */

    #ifndef _Included_com_jason_jni_demo2_NdkTest
    #define _Included_com_jason_jni_demo2_NdkTest
    #ifdef __cplusplus
    extern "C" {
    #endif
    /*
     * Class:     com_jason_jni_demo2_NdkTest
     * Method:    getString
     * Signature: ()Ljava/lang/String;
     */
    JNIEXPORT jstring JNICALL Java_com_jason_jni_demo2_NdkTest_getString
      (JNIEnv *, jobject);

    #ifdef __cplusplus
    }
    #endif
    #endif

編寫標頭檔案對應的NdkTest.c檔案實現getString方法

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_jason_jni_demo2_NdkTest */

#ifndef _Included_com_jason_jni_demo2_NdkTest
#define _Included_com_jason_jni_demo2_NdkTest
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class:     com_jason_jni_demo2_NdkTest
* Method:    getString
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_jason_jni_demo2_NdkTest_getString
(JNIEnv * env, jclass clazz){
   char * hello = "Hello World JNI2";
         return  (*env)->NewStringUTF(env,hello);
}

#ifdef __cplusplus
}
#endif
#endif

3、檔案編寫好後,就剩下Android.mk和Application.mk了,可根據自己情況編寫,下面提供一個簡單的demo

Android.mk具體內容:

    LOCAL_PATH := $(call my-dir)

    include $(CLEAR_VARS)

    LOCAL_MODULE    := test_ndk
    LOCAL_SRC_FILES := NdkTest.c

    include $(BUILD_SHARED_LIBRARY)

Application.mk具體內容:

    APP_MODULES := test_ndk
    APP_ABI := all

4、萬事俱備,只差編譯了,這時配置的ndk-build命令又派上用場了,選中jni目錄右鍵——>External Tool——>ndk-build
這裡寫圖片描述
執行完這個命令後,會在jni同級目錄生成libs目錄和對應的so庫,這時候就可以像之前一樣使用了,但需要注意的是AndroidStudio 預設指定是載入jniLibs下的so,所以需要把libs目錄改為jniLibs或者
在build.gradle裡指定so的目錄

sourceSets {
   main {
       jniLibs.srcDirs = ['src/main/libs']
   }
}

另外還有個問題需要注意,如果是在AndroidStudio裡直接這樣編譯apk會出現編譯出錯,如下:

  FAILURE: Build failed with an exception.

    * What went wrong:
    Execution failed for task ':app:compileDebugNdk'.
    > Error: Your project contains C++ files but it is not using a supported native build system.
    Consider using CMake or ndk-build integration with the stable Android Gradle plugin:
     https://developer.android.com/studio/projects/add-native-code.html
    or use the experimental plugin:
     https://developer.android.com/studio/build/experimental-plugin.html.


    * Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

    BUILD FAILED

這是因為如果’src/main/jni’存在的話,AndroidStudio會採用自帶的方式去編譯生成so庫,此時可以在build.gralde新增如下程式碼修復此問題:

    defaultConfig {
        applicationId "com.jason.jni.demo2"
        minSdkVersion 21
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        sourceSets {
            main {
                jniLibs.srcDirs = ['src/main/libs']
                jni.srcDirs = [] jni目錄存在AndroidStudio會採用自身方式生成so庫,需要配置這個,不然編譯專案時候會出現上面的錯誤
            }
        }
    }