Android中JNI使用詳解(1)---Eclipse中NDK配置So檔案生成
1、NDK下載和配置
NDK下載地址:http://www.androiddevtools.cn/
NDK下載完成後,選擇Eclipse上方Window選單Preferences - Android - NDK 在NDK Location中配置NDK絕對路徑。
`
2、安裝下載CDT外掛
選擇Eclipse上方的Help選單-Inatall New SoftWare在Work with:後輸入CDT - http://download.eclipse.org/tools/cdt/releases/juno
3、檢視JNI示例
在下載的NDK中samples目錄下有hello-jni等例子,可通過執行例子來了解jni工作原理。先觀察jni資料夾,一般裡面有三個檔案,分別為Android.mk、Application.mk、jni.c檔案;
4、Android.mk介紹
Android.mk:用於配置編譯生成的so庫名、引用的標頭檔案(.h
(1)LOCAL_PATH: 這個變數用於給出當前檔案的路徑。
必須在 Android.mk 的開頭定義,可以這樣使用:LOCAL_PATH := $(call my-dir)
如當前目錄下有個資料夾名稱 src
這個變數不會被$(CLEAR_VARS)清除,因此每個 Android.mk 只需要定義一次(即使在一個檔案中定義了幾個模組的情況下)。
(2)LOCAL_MODULE: 這是模組的名字,它必須是唯一的,而且不能包含空格。
必須在包含任一的$(BUILD_XXXX)指令碼之前定義它。模組的名字決定了生成檔案的名字。
(3)LOCAL_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檔案。
(4)LOCAL_C_INCLUDES: 可選變數,表示標頭檔案的搜尋路徑。
預設的標頭檔案的搜尋路徑是LOCAL_PATH目錄。
(5)LOCAL_STATIC_LIBRARIES: 表示該模組需要使用哪些靜態庫,以便在編譯時進行連結。
(6)LOCAL_SHARED_LIBRARIES: 表示模組在執行時要依賴的共享庫(動態庫),在連結時就需要,以便在生成檔案時嵌入其相應的資訊。
注意:它不會附加列出的模組到編譯圖,也就是仍然需要在Application.mk 中把它們新增到程式要求的模組中。
(7)LOCAL_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的區別,暫時還不清楚。
(9)LOCAL_JNI_SHARED_LIBRARIES:定義了要包含的so庫檔案的名字,如果程式沒有采用jni,不需要
LOCAL_JNI_SHARED_LIBRARIES := libxxx 這樣在編譯的時候,NDK自動會把這個libxxx打包進apk; 放在youapk/lib/目錄下
5、Application.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檔案的工作就完成了。
9、so檔案的呼叫
在HelloJni.java檔案中有一段程式碼:
static {
System.loadLibrary("hello-jni");
}
使用loadLibrary就可以載入該so檔案了,載入的時候不需要寫libhello-jni.so,只要寫hello-jni就可以了。