Android NDK開發(fā)輕松入門
簡介:
AndroidNDK是能使Android應(yīng)用開發(fā)者把從c/c++編譯而來的本地代碼嵌入到應(yīng)用包中的一系列工具的組合。
注意:
AndroidNDK只能用于Android1.5及以上版本中。
I. Android NDK 目標(biāo):
Android虛擬機允許你的應(yīng)用在源碼中通過JNI調(diào)用本地代碼中實現(xiàn)的方法們。概括起來,這表示:
-你的應(yīng)用的源中要聲明一個或多個方法,這些方法前面需有'native'關(guān)鍵字,這表明它們被本地代碼實現(xiàn)。如:
- nativebyte[] loadFile(String filePath);
-你必須提供本地的共享庫,庫中包含這些方法的實現(xiàn)。這個庫將會打包你的應(yīng)用.apk中。這個庫的命名必須符合標(biāo)準(zhǔn)的Unix命名規(guī)則,也就是:lib<something>.so這種形式。并且還要包含一個標(biāo)準(zhǔn)的JNI入口。例如:
libFileLoader.so
-你的應(yīng)用必須顯式的加載本地庫。例如,要在應(yīng)用啟動時加載,只需簡單地在代碼中增加如下語句:
- static{
- System.loadLibrary("FileLoader");
- }
注意寫庫的名字時你不需要使用'lib'前綴和'.so'后綴。
AndroidNDK只是AndroidSDK的一個組件,它幫助你:
-產(chǎn)生JNI兼容的共享庫,此庫能運行于跑在ARMCPU上的Android1.5及以上系統(tǒng)。
-把共享庫考貝到你的應(yīng)用的項目中的合適的位置,并最終把它們添加到你的.apks中。
-在后續(xù)的NDK版本中,我們打算提供通過遠(yuǎn)程gdb調(diào)試本地代碼的工具并盡量多地提供源碼和符號信息。
AndroidNDK還提供了:
-一系列跨平臺的編譯工具(編譯器,鏈接器,等等),它們可以在Linux,OS X 和 Windows (使用Cygwin)上產(chǎn)生ARM上的二進(jìn)制程序碼。
-一系列的頭文件,對應(yīng)于Android系統(tǒng)所支持的穩(wěn)定的本地API們,這保證了你所用的接口在后續(xù)所有版本中依舊被支持。
重點注意:
記住大多數(shù)系統(tǒng)庫并沒有固定死并且可能在未來的版本中會發(fā)生重大變化,甚至被刪除,但是”穩(wěn)定的API們”是不變的。
-一個構(gòu)建系統(tǒng),使得開發(fā)者只需寫少量編譯文件描述哪些源文件需被構(gòu)建即可。構(gòu)建系統(tǒng)可處理所有編譯工具鏈/平臺/CPU/ABI細(xì)節(jié)。還有,后續(xù)的NDK更新中可以在添加更多的編譯工具鏈,平臺,系統(tǒng)接口的同時不需開發(fā)者的項目構(gòu)建文件發(fā)生變化。
II.Android NDK 不想做的:
使用NDK編寫運行于android設(shè)備上的一般本地代碼這種方式并不好。你的應(yīng)用依然應(yīng)該使用Java編寫,正確處理Android系統(tǒng)的事件來避免"應(yīng)用無反應(yīng)"對話框的出現(xiàn)或處理應(yīng)用的生命周期。
注意,無論如何還是可以通過本地代碼編寫精巧的應(yīng)用的,這個應(yīng)用上只是帶有一個很小的用于啟動/關(guān)閉應(yīng)用的包裝。
對JNI的深刻理解是非常必要的。因為在這個環(huán)境中的很多操作需要開發(fā)者做出一些特殊的處理,而它們在典型的一般代碼(java)中是不需要的。這些包括:
-不能通過指針直接使用VM對象的內(nèi)容。例如,你無法安全地獲取一個指向java字符串對象的16位字符數(shù)組的指針然后在一個循環(huán)中枚舉它的每一項。
-當(dāng)本地代碼想要在不同的JNI調(diào)用之間保存VM對象的句柄時,需要對句柄進(jìn)行明確的引用管理。
NDK僅僅為被android系統(tǒng)支持的本地API和庫中很少的一些提供了頭文件。然而一個典型的Android系統(tǒng)映像包含了很多本地共享庫,但這些應(yīng)被看做是實現(xiàn)的細(xì)節(jié),這些實現(xiàn)可能在平臺更新或發(fā)布時產(chǎn)生徹底的變化。
如果一個Android系統(tǒng)的庫沒有被NDK的頭文件明確支持,那么應(yīng)用不應(yīng)依賴于它。否則可能在下一次系統(tǒng)升級后出現(xiàn)杯具。
選中的系統(tǒng)庫將逐漸地被添加到穩(wěn)定版的NDKAPI中。
III.NDK 開發(fā)實踐:
下面是一個對使用NDK開發(fā)本地代碼過程的粗略的概覽:
1/將你的本地代碼源碼放在路徑$PROJECT/jni/下。
2/寫一個文件:$PROJECT/jni/Android.mk,來描述你的源文件們。
3/可選的:在文件$PROJECT/jni/Application.mk中描述你的項目的更多細(xì)節(jié)。盡管你不需要從頭寫,但你可以處理多CPU問題以及改寫編譯/鏈接選項。(更多細(xì)節(jié)請觀docs/APPLICATION-MK.html )。
4/在你的項目路徑下或其任何子路徑下運行"$NDK/ndk-build"來編譯你的本地代碼。
***一步將在編譯成功時復(fù)制你的應(yīng)用所需共享庫到你項目的跟路徑下。然后你可以用跟以前一樣的方式產(chǎn)生最終的.apk文件。
下面,是一些更多的細(xì)節(jié):
III.1/配置NDK:
以前的發(fā)行版需要你運行'build/host-setup.sh'腳本來配置你的NDK。但是這一步從第4版(NDK r4)開始被移除了。
III.2/放置 C 和 C++源碼:
將你的本地源碼放在以下路徑下:
$PROJECT/jni/
$PROJECT對應(yīng)你的android應(yīng)用項目的路徑。
你可以隨意組織jni下的內(nèi)容,路徑名和路徑結(jié)構(gòu)不會影響到最終產(chǎn)生的應(yīng)用包。所以你無需使用類似于com.<mycompany>.<myproject>這樣的名字。
注意 C和C++源碼都是被支持的。默認(rèn)C++文件擴展名是'.cpp',但是其它的擴展名也可以被處理。(見文檔docs/ANDROID-MK.html).
也可以通過調(diào)整文件Android.mk的內(nèi)容,把你的源碼存放在其它路徑下。
III.3/寫一個Android.mk構(gòu)建腳本:
一個 Android.mk文件是一個很小的構(gòu)建腳本。你編寫它以描述你給NDK構(gòu)建器的源碼文件們。它的語法在docs/ANDROID-MK.html中有詳細(xì)描述。
NDK簡單的將你的原文件組織到多個"模塊"中,每個模塊可以是以下的任意一種:
-一個靜態(tài)庫
-一個共享庫
你可以在一個Android.mk中定義多個模塊或?qū)懚鄠€Android.mk文件,每個文件只對應(yīng)一個模塊。
注意,一個Android.mk文件可能被構(gòu)建系統(tǒng)分析多遍,所以不要假設(shè)某個變量沒有被定義。默認(rèn)下,NDK將尋找下面的構(gòu)建腳本:
$PROJECT/jni/Android.mk
如果你想在子路徑下定義Android.mk文件,你應(yīng)該在頂層的Android.mk中包含它們。有個函數(shù)可以做到這個功能:
- include$(call all-subdir-makefiles)
這將會包含當(dāng)前構(gòu)建路徑的所有子路徑下的Android.mk文件們。
III.4/寫一個Application.mk構(gòu)建文件(可選):
Android.mk描述你要構(gòu)建的模塊們,而Application.mk文件描述你的應(yīng)用自身。看文檔docs/APPLICATION-MK.html來了解這個文件允許你做什么。這個文件主要包含:
-你的應(yīng)用所需要模塊的準(zhǔn)確列表。
-產(chǎn)生的機器碼所對應(yīng)的CPU架構(gòu)。
-可選的信息,像你要構(gòu)建release還是debug,特殊的C或 C++編譯參數(shù)以及其它需要應(yīng)用到所有模塊的構(gòu)建選項。
這個文件是可選的:默認(rèn)情況下,NDK將構(gòu)建在Android.mk中列出的所有模塊的并且默認(rèn)面向CPUABI (armeabi).
有兩種方法使用一個Application.mk:
-將它放在$PROJECT/jni/Application.mk位置,那么它會被'ndk-build'腳本自動使用。
-將它放在$NDK/apps/<name>/Application.mk,$NDK代表你的NDK安裝路徑。之后,在NDK路徑下運行"make APP=<name>"。
這是在NDKr4之前的辦法。出于兼容的原因,當(dāng)前還是被支持的,但是我們強烈鼓勵你使用***種方法。因為它簡單并且不用改動NDK安裝路徑下的路徑樹結(jié)構(gòu)。
III.5/調(diào)用NDK構(gòu)建系統(tǒng):
使用NDK構(gòu)建機器代碼的***方式是使用'ndk-build'腳本。你也可以使用另一個老的方式--依賴于創(chuàng)建'$NDK/apps'子目錄的方式。
不論哪種方式,編譯成功后,那些編譯出的“裸體”(不帶有調(diào)試信息的)二進(jìn)制模塊都將被復(fù)制到你應(yīng)用項目所在的路徑下(注意非“裸體”的二進(jìn)制模塊會保留以提供調(diào)試能力。沒有必要把非“裸體”模塊復(fù)制到設(shè)備上去)。
1:使用'ndk-build'命令:
'ndk-build'腳本可以在NDK安裝所在的***目錄下找到,可以直接你的應(yīng)用項目的目錄(也就是你的AndroidManifest.xml所在的目錄)或任何子目錄下調(diào)用。
例如:
cd$PROJECT $NDK/ndk-build
這將啟動NDK構(gòu)建腳本,腳本將自動探測你的開發(fā)系統(tǒng)和應(yīng)用項目文件來決定構(gòu)建什么東西。
例如:
ndk-build ndk-build clean -->清空所編譯出的二進(jìn)制文件們。 ndk-build -B V=1 -->強制完全重新編譯,并顯示命令
默認(rèn)下,腳本希望看到一個可選的$PROJECT/jni/Application.mk和一個必須的$PROJECT/jni/Android.mk。
成功后,會把產(chǎn)生的二進(jìn)制模塊(即共享庫)復(fù)制到你的項目樹中的合適位置。你可以在之后使用’ant’命令或ADP插件來重建完整的應(yīng)用包。
關(guān)于這個腳本的更完整的說明和可用的選項,見docs/NDK-BUILD.html。
2:使用$NDK/apps/<name>/Application.mk:
這種構(gòu)建方式是NDKr4以及正前版本的唯一選擇,當(dāng)前還支持,僅僅是為了兼容的原因。我們強烈建議你麻溜地移植為使用'ndk-build'命令的方式,因為我們可能很快就把這種方式拋棄掉。
用它需要這樣做:
1.在你的NDK安裝目錄下(不是你的應(yīng)用路徑)創(chuàng)建一個子目錄,叫:$NDK/apps/<name>/。<name>是一個任意的名字用來向NDK構(gòu)建系統(tǒng)描述你的應(yīng)用(不能有空格)。
2.寫一個$4NDK/apps/<name>/Application.mk,需在里面定義一個APP_PROJECT_PATH指向你的應(yīng)用項目目錄。
3.在命令行中,進(jìn)入到NDK安裝路徑,然后調(diào)用頂層的GNUMakefile,如下:
- cd$NDK
- makeAPP=<name>
結(jié)果同***種方法一樣,除了一些中間產(chǎn)物放在$NDK/out/apps/<name>/下之外。
IV.重建你的應(yīng)用包:
使用NDK產(chǎn)生二進(jìn)制文件后,你需是用通常的方式重建的你應(yīng)用包文件(.apk),即使用'ant'命令或ADTEclipse插件。
你的新.apk中將被嵌入共享庫文件,然后在安裝到設(shè)備時被系統(tǒng)自動分離出來。
V.對調(diào)試的支持:
NDK提供了一個輔助腳本,叫做'ndk-gdb',來十分輕松地為你的應(yīng)用啟動一個調(diào)試會話。
本地調(diào)試只能在運行Android2.2或更高系統(tǒng)的設(shè)備上執(zhí)行。并且不需要特殊用戶權(quán)限。
更多信息,請對docs/NDK-GDB.html。簡要來說,本地調(diào)試分以下幾步:
1.確定你的應(yīng)用是可調(diào)試的(在AndroidManifest.xml中設(shè)置android:debuggable為"true")。
2.使用'ndk-build'構(gòu)建你的共享庫,然后構(gòu)建你的應(yīng)用然后安裝到設(shè)備或模擬器上。
3.運行你的應(yīng)用。
4.在你的應(yīng)用項目目錄下運行'ndk-gdb'。
你將看到gdb提示符出現(xiàn)。然后扒著GDB手冊笨笨的調(diào)吧。