1. 程式人生 > >Android中JNI使用詳解(1)---Eclipse中NDK配置So檔案生成

Android中JNI使用詳解(1)---Eclipse中NDK配置So檔案生成

1NDK下載和配置

NDK下載地址:http://www.androiddevtools.cn/

NDK下載完成後,選擇Eclipse上方Window選單Preferences - Android - NDK NDK Location中配置NDK絕對路徑。

`

2、安裝下載CDT外掛 

選擇Eclipse上方的Help選單-Inatall New SoftWareWork with:後輸入CDT - http://download.eclipse.org/tools/cdt/releases/juno 

然後等待勾選CDT Main Features和 CDT Optional Features然後點選Next,等下載完成重啟Eclipse即可。 


3、檢視JNI示例

在下載的NDKsamples目錄下有hello-jni等例子,可通過執行例子來了解jni工作原理。先觀察jni資料夾,一般裡面有三個檔案,分別為Android.mkApplication.mkjni.c檔案;


4Android.mk介紹

Android.mk:用於配置編譯生成的so庫名、引用的標頭檔案(.h

檔案)、需要編譯的.c檔案和.a靜態庫檔案等。要掌握jni,必須瞭解Android.mk裡面變數的作用和規範。


1LOCAL_PATH:  這個變數用於給出當前檔案的路徑。 
       必須在 Android.mk 的開頭定義,可以這樣使用:LOCAL_PATH := $(call my-dir) 
       如當前目錄下有個資料夾名稱 src

,則可以這樣寫 $(call src),那麼就會得到 src 目錄的完整路徑 
       這個變數不會被$(CLEAR_VARS)清除,因此每個 Android.mk 只需要定義一次(即使在一個檔案中定義了幾個模組的情況下)。 


      (2LOCAL_MODULE: 這是模組的名字,它必須是唯一的,而且不能包含空格。 
       必須在包含任一的$(BUILD_XXXX)指令碼之前定義它。模組的名字決定了生成檔案的名字。 


      (3LOCAL_SRC_FILES:  這是要編譯的原始碼檔案列表。 
       只要列出要傳遞給編譯器的檔案,因為編譯系統自動計算依賴。注意原始碼檔名稱都是相對於 LOCAL_PATH的,你可以使用路徑部分,例如: 
        LOCAL_SRC_FILES := foo.c toto/bar.c\ Hello.c 
       檔案之間可以用空格或Tab鍵進行分割,換行請用"\" 
       如果是追加原始碼檔案的話,請用LOCAL_SRC_FILES += 
       注意:可以LOCAL_SRC_FILES := $(call all-subdir-java-files)這種形式來包含local_path目錄下的所有java檔案。 


    (4LOCAL_C_INCLUDES:  可選變數,表示標頭檔案的搜尋路徑。 
        預設的標頭檔案的搜尋路徑是LOCAL_PATH目錄。 


    (5LOCAL_STATIC_LIBRARIES: 表示該模組需要使用哪些靜態庫,以便在編譯時進行連結。 


    (6LOCAL_SHARED_LIBRARIES:  表示模組在執行時要依賴的共享庫(動態庫),在連結時就需要,以便在生成檔案時嵌入其相應的資訊。 
       注意:它不會附加列出的模組到編譯圖,也就是仍然需要在Application.mk 中把它們新增到程式要求的模組中。 


    (7LOCAL_LDLIBS:  編譯模組時要使用的附加的連結器選項。這對於使用‘-l’字首傳遞指定庫的名字是有用的。 
       例如,LOCAL_LDLIBS := -lz表示告訴連結器生成的模組要在載入時刻連結到/system/lib/libz.so 
       可檢視 docs/STABLE-APIS.TXT 獲取使用 NDK發行版能連結到的開放的系統庫列表。 


     (8)LOCAL_MODULE_PATH 和 LOCAL_UNSTRIPPED_PATH 
       在 Android.mk 檔案中, 還可以用LOCAL_MODULE_PATH LOCAL_UNSTRIPPED_PATH指定最後的目標安裝路徑
       不同的檔案系統路徑用以下的巨集進行選擇: 
       TARGET_ROOT_OUT:表示根檔案系統。 
       TARGET_OUT:表示 system檔案系統。 
       TARGET_OUT_DATA:表示 data檔案系統。 
       用法如:LOCAL_MODULE_PATH :=$(TARGET_ROOT_OUT) 
       至於LOCAL_MODULE_PATH LOCAL_UNSTRIPPED_PATH的區別,暫時還不清楚。 


   (9LOCAL_JNI_SHARED_LIBRARIES:定義了要包含的so庫檔案的名字,如果程式沒有采用jni,不需要 
        LOCAL_JNI_SHARED_LIBRARIES := libxxx 這樣在編譯的時候,NDK自動會把這個libxxx打包進apk; 放在youapk/lib/目錄下 


5Application.mk介紹

Application.mk:用於配置JNI生成該CPU使用so的檔案格式如下:

APP_ABI := armeabi armeabi-v7a x86 arm64-v8a x86_64 mips mips64

TARGET_CPU_API :=armeabi armeabi-v7a x86 arm64-v8a x86_64 mips mips64

或者 配置所有

APP_ABI := all


6.c檔案介紹

.c檔案是Jni中主要編譯檔案,下面以hello-jni.c進行介紹;

jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz )
{
    return (*env)->NewStringUTF(env, "Hello from JNI !");
}

這個函式名根據src下的HelloJni,java中的函式public native String stringFromJNI();生成的。命名規則為:

Java_(固定開頭)com_example_hellojni(_連線的包名)_HelloJni(類名)_stringFromJNI(函式名)

 

這個函式的生成可以使用javah的命令:用命令列方式進入工程目錄的bin\classes目錄下,執行javah com.example.hellojni.HelloJni,就會把所有native的函式都按規則生成在一個名為HelloJni.h的標頭檔案裡。


7新建並配置一個新的Builder

    1) 點選Project->Properties->Builders->New,新建立一個Builder。在彈出的對話方塊上面點選Program,點選OK

    2) 在彈出的對話方塊【Edit Configuration】中,配置選項卡【Main】:

               Location中需要填入nkd-build.cmd的路徑(NDK安裝目錄下)。

               WorkingDiretcoty中需要填入HelloJni的工程根目錄。

    3) 在【EditConfiguration】中,配置選項卡【Refresh】:

              勾選“Refresh resources upon completion”,

              勾選“The entire workspace”,

              勾選“Recuresively include sub-folders”。

    4)在【EditConfiguration】中,配置選項卡【Build Options】:

             勾選“After a Clean””,

             勾選“During manual builds”,

             勾選“During auto builds,

             勾選“Specify working set of relevant resources”。

             點選“Specify Resources…”勾選TestNDK工程的“jni“目錄,Finish

      儲存設定,點選OK


8、生成so檔案的方法

   由於我們勾選了“During auto builds”,所以在工程有所改變的時候,so檔案便會自動編譯,正確生成以後就能在工程目錄下發現多了兩個資料夾,資料夾libs\armeabi目錄下生成了一個叫libhello-jni.so的檔案。至此,使用NDK生成so檔案的工作就完成了。


9so檔案的呼叫

    在HelloJni.java檔案中有一段程式碼:

    static {
        System.loadLibrary("hello-jni");
    }

    使用loadLibrary就可以載入該so檔案了,載入的時候不需要寫libhello-jni.so,只要寫hello-jni就可以了。