鍍金池/ 教程/ Android/ 概述
安裝 NDK
application.mk
調(diào)試
Android.mk 文件
Hello JNI 示例
概述
Box2D 的 Android NDK 實(shí)現(xiàn)
TwoLibs 示例

概述

注意:在 Windows 上運(yùn)行 NDK 需要有 Cygwin 支持,個(gè)人建議使用 Ubuntu 為好 。

介紹:

Android SDK 是一個(gè)允許 Android 應(yīng)用開發(fā)人員使用 C 或 C++源文件編譯并嵌入到本機(jī)源代碼中的應(yīng)用程序包的一組工 具。

重要說(shuō)明:

Android NDK 只能用于 android 1.5 以上版本

1. Android NDK 的目的:

Android 虛擬機(jī)允許你的應(yīng)用程序源代碼通過(guò) JNI 調(diào)用在本地實(shí)現(xiàn)的源代碼,簡(jiǎn)單的說(shuō),這就意味著:

—-你的應(yīng)用程序?qū)⒙暶饕粋€(gè)或多個(gè)用’native’關(guān)鍵字的方法用來(lái)指明它們是通過(guò)本地代碼實(shí)現(xiàn)的 例如:

    native byte[] loadFile(String filePath)

—-你必須提供包含實(shí)現(xiàn)這些方法的共享庫(kù)(就是.so),將共享庫(kù)打包到你的應(yīng)用程序包 apk 中,這些庫(kù)文件必須根據(jù) 標(biāo)準(zhǔn)的 Unix 約定來(lái)命名為 lib.so,并且是需要包含一個(gè)標(biāo)準(zhǔn)的 JNI 的接口,例如

     libFileLoader.so

—-你的應(yīng)用程序必須明確的裝載這些庫(kù)文件(.so文件),比如,在程序的開始裝載它,只需要簡(jiǎn)單的添加幾句源代碼:

    static {

    System.loadLibrary(“FileLoader”);

    }

注意:這里你不必再將前綴 lib 和后綴.so 寫入。

Android NDK 對(duì)于 Android SDK 只是個(gè)組件,它可以幫你:

—-生成的 JNI 兼容的共享庫(kù)可以在大于 Android1.5 平臺(tái)的 ARM CPU 上運(yùn)行

—-將生成的共享庫(kù)拷貝到合適的程序工程路徑的位置上,以保證它們自動(dòng)的添加到你的 apk 包中(并且簽名的)

—-在以后的版本中,我們將提供來(lái)幫助你的源代碼通過(guò)遠(yuǎn)程 gdb 連接和盡可能多的源代碼的信息。

而且,Android NDK 還提供:

—-一組交叉編譯鏈(編譯器、鏈接器等)來(lái)生成可以在 Linux,OS X 和 Windows (用 Cygwin )運(yùn)行的二進(jìn)制文件

—-一組與由 Android 平臺(tái)提供的穩(wěn)定的本地 API 列表的頭文件

它們?cè)?docs/STABLE-APIS.html 中有說(shuō)明

重要提示:

記住,在以后的更新和發(fā)布平臺(tái)中,Android 系統(tǒng)鏡像中的大多數(shù)本地系統(tǒng)庫(kù)并不是一成不變的,而是可以徹底改變, 甚至刪除的

—-一個(gè)編譯系統(tǒng)(build system)可以允許開發(fā)者寫一個(gè)非常短的編譯文件(build files)去描述哪個(gè)源代碼需要編譯,并且怎樣編譯。編譯系統(tǒng)可以解決所有的 toolchain/platform/CPU/ABI 細(xì)節(jié)的問(wèn)題。并且,較晚的 NDK 版 本中還添加了更多的可以不用改變開發(fā)者的編譯文件的情況下的 toolchains,platforms,系統(tǒng)接口

2. Android NDK 的缺點(diǎn)

NDK 并不是一個(gè)可以編寫通用的源代碼并且可以在 Android 設(shè)備上運(yùn)行的方法,你的應(yīng)用程序還是需要使用 JAVA 程序,適當(dāng)?shù)奶幚硐到y(tǒng)事件來(lái)避免“應(yīng)用程序沒有反應(yīng)”的對(duì)話框或者處理 Android 應(yīng)用程序的生命周期

注意:可以適當(dāng)?shù)脑谠创a中寫一個(gè)復(fù)雜的應(yīng)用程序,用于啟動(dòng)/停止一個(gè)小型的“應(yīng)用程序包”

強(qiáng)烈建議很好地理解的 JNI,因?yàn)樵S多操作在這種環(huán)境要求的開發(fā)人員,都采取具體的行動(dòng),不一定在常見典型的本機(jī)代碼。這些措施包括:

—-不能通過(guò)指針直接訪問(wèn) VM 的對(duì)象。比如:你不能安全的得到一個(gè)指向 String 對(duì)象的 16 位 char 數(shù)組的循環(huán)遍歷

—-需要顯示引用管理本機(jī)代碼時(shí)候要保持處理 JNI 調(diào)用之間的 VM 對(duì)象

NDK 在 Android 平臺(tái)僅僅提供了有限的本地 API 和庫(kù)文件的支持的系統(tǒng)頭文件,然而一個(gè)標(biāo)準(zhǔn)的 Android 系統(tǒng)鏡像包括許多本地共享庫(kù),這些都應(yīng)該被考慮在更新和發(fā)行版本的可以徹底改變的實(shí)現(xiàn)細(xì)節(jié)

如果 Android 系統(tǒng)庫(kù)沒有明確的被 NDK 明確的支持,然后應(yīng)用程序不應(yīng)該依賴于它提供的,或者打破了將來(lái)在各種設(shè)備上的無(wú)線系統(tǒng)更新

選定的系統(tǒng)庫(kù)將逐漸被添加到穩(wěn)定的 NDK API 中

3. NDK開發(fā)實(shí)踐

下面將給出一個(gè)怎樣用 Android NDK 開發(fā)本地代碼的粗略的概述

(1) 把本地代碼放在 $PROJECT/jni/…下,比如將 hello.c 放到 apps/hello/jni/目錄下

(2) 在你的 NDK 編譯系統(tǒng)中在 $PROJECT/jni/Android.mk 來(lái)描述你的源代碼

(3) 可選:在 $PROJECT/jni/Application.mk 到你的編譯系統(tǒng)中來(lái)詳細(xì)描述你的項(xiàng)目,盡管你開始的話不一定需要它, 但是它允許你使用更多的 CPU 或者覆蓋編譯器/鏈接器的標(biāo)記(看 docs/APPLICATION-MK.html 了解更多細(xì)節(jié))

(4) 從你的項(xiàng)目的目錄開始通過(guò)運(yùn)行”$NDK/ndk-build”來(lái)編譯你的代碼,或者從子目錄開始

(5) 最后一步可以 copy,萬(wàn)一成功,剝離共享庫(kù)的應(yīng)用層序需要你的應(yīng)用程序的項(xiàng)目根目錄。然后你通過(guò)通常的方法來(lái) 生成最終的 apk

現(xiàn)在,開始一些更 的細(xì)節(jié)

① 配置 NDK

以前的發(fā)行版本需要你運(yùn)行“build/host-setup.sh”腳本來(lái)配置你的 NDK。從 release 4(NDK r)以后就完全去除了這一步

② 放置 C/C++ 代碼

假如我們創(chuàng)建的是 test 目錄,創(chuàng)建的代碼 hello.c

把 hello.c 放到 test/jni 目錄下

這個(gè)項(xiàng)目的位置相當(dāng)于你的 Android 應(yīng)用程序項(xiàng)目的路徑

這樣你就很輕松的組織起來(lái)了你想要的 jni 的目錄,這里項(xiàng)目目錄的名字和結(jié)構(gòu)不會(huì)影響到最終生成的 apk,所以 你不必用類似于 com.. 作為應(yīng)用程序包名

注意,NDK 是支持 C 和 C++ 的,NDK 支持的 C++ 文件擴(kuò)展名是’.cpp’,但是其他的擴(kuò)展名也是可以被處理的 (看 docs/ANDROID-MK.html 了解更多)

它可以通過(guò)調(diào)整你的 Android.mk 文件來(lái)將源代碼放在不同的位置

③ 創(chuàng)建一個(gè) Android.mk 編譯腳本

Android.mk 文件是一個(gè)小型的編譯腳本,你可以在 NDK 編譯系統(tǒng)中用它來(lái)描述你的源代碼。更詳細(xì)的描述在 docs/ANDROID-MK.html 中

總而言之,NDK 將你的源代碼聚合到模塊(modules)中,每個(gè)模塊可以執(zhí)行下列之一

—-一個(gè)靜態(tài)庫(kù)(lib.a)

—-一個(gè)動(dòng)態(tài)庫(kù)(lib.so)

你可以在 Android.mk 中定義多個(gè)模塊,或者你可以編寫多個(gè) Android.mk 文件,每一個(gè)定義一個(gè)單獨(dú)的模塊

注意,單獨(dú)的 Android.mk 也行被編譯系統(tǒng)多次解析,以確定哪些變量沒有被定義。

默認(rèn)地,NDK 會(huì)通過(guò)如下的編譯腳本去尋找

test/jni/Android.mk(存放位置)

如果你想定義 Android.mk 到子目錄中,你需要在最高層的 Android.mk 中明確的包含它們,下面是一個(gè)幫助的方法可以實(shí)現(xiàn)這個(gè)功能。

    include $(call all-subdir-makefiles)

它會(huì)將所有的在子目錄中的 Android.mk 文件加入到當(dāng)前編譯文件的路徑中

④ 寫一個(gè) Application.mk 編譯文件(可選)

在你的編譯系統(tǒng)中有一個(gè) Android.mk 文件描述模塊的同時(shí),Application.mk 文件藐視你的應(yīng)用程序本身。請(qǐng)看 docs/APPLICATION-MK.html 文檔來(lái)理解這個(gè)文件允許我們做什么。這包括

—-你的應(yīng)用程序需要模塊的準(zhǔn)確清單

—-CPU 架構(gòu)生成機(jī)器代碼

—-可選信息,你是否需要一個(gè) release 或者 debug build,特殊的 C/C++ 編譯器標(biāo)志和其他適用于所有模塊的 build

這個(gè)文件是可選文件:默認(rèn)地,NDK 會(huì)提供一個(gè)對(duì)于所有的在你的 Android.mk(所有的 makefiles 都在里面)中的所有模塊的簡(jiǎn)單編譯并且指定默認(rèn)的 CPU ABI

使用 Application.mk 有兩種方法:

—-把它放到 test/jni/Application.mk,它就會(huì)自動(dòng)的被’ndk-build’腳本找出來(lái)

—-把它放在 NDK//Application.mk,也就是 NDK 安裝的路徑下,然后從 NDK 目錄下執(zhí)行”make APP=

這個(gè)方法是 Android NDK r4 以前的?,F(xiàn)在仍然兼容。但是我們強(qiáng)烈建議你使用第一種方法,因?yàn)樗?jiǎn)單并且不用修改 NDK 安裝樹的目錄。

再次看看 docs/APPLICATION-MK.html 對(duì)于它的完整說(shuō)明

⑤ 調(diào)用 NDK 編譯系統(tǒng)

用 NDK 編譯成機(jī)器碼的最好方法是使用”ndk-build”腳本,你還可以使用第二個(gè),這取決于你早起常見的”$NDK/apps”子目錄

在兩種情況下,成功構(gòu)建將 copy 應(yīng)用程序所需的最終的已經(jīng)剝離的二進(jìn)制模塊(即共享庫(kù))到應(yīng)用程序的項(xiàng)目路徑中(注意,未剝離的版本主要是用于調(diào)試目的,無(wú)需拷貝未剝離的二進(jìn)制文件到設(shè)備中)

[1]:使用’ndk-build’命令

‘ndk-build’腳本位于NDK安裝目錄最頂層,可以直接被應(yīng)用程序項(xiàng)目目錄(你的AndroidManifest.xml文件所在位置)或者其他任何子目錄

$ cd $PROJECT

$ $NDK/ndk-build(注意是 $NDK/ndkbuild,這是個(gè)命令) 將啟動(dòng) NDK 的 build 腳本,它會(huì)自動(dòng)探測(cè)您開發(fā)的系統(tǒng)和應(yīng)用程序項(xiàng)目文件,以確定 build 設(shè)么

例如:

$ndk-build

$ndk-build clean à 清理生成的二進(jìn)制文件

$ndk-build –B V=1 à 強(qiáng)制完全重新 build,顯示命令

默認(rèn)的,它期望的是可選文件 $PROJECT/jni/Application.mk 和必須的文件 $PROJECT/jni/Android.mk

成功的話,它講話就復(fù)制生成的二進(jìn)制模塊(即共享庫(kù).so文件)到你的項(xiàng)目樹中的適當(dāng)位置。您可以在以后重新 build 完整的 Android 應(yīng)用程序包或者通過(guò)“ant”命令,或者 ADT 插件。

可以看 docs/NDK-BUILD.html 來(lái)了解更多的信息

[2]:使用 $NDK/apps//Application.mk

這種 build 方法是在 Android NDK r4 版本之前的,不過(guò)依然兼容現(xiàn)在的。我們強(qiáng)烈建議您盡可能的使用’ndk-build’,因?yàn)槲覀兛赡軙?huì)刪除在以后的 NDK 發(fā)行版本中的支持

① 創(chuàng)建一個(gè)子目錄為 $NDK/apps//

② 在 $NDK/apps//目錄下寫一個(gè) Application.mk 文件,然后需要定義一個(gè) APP_PROJECT_PATH 來(lái)執(zhí)行你的應(yīng)用程序項(xiàng)目的目錄。

③ 進(jìn)入到 NDK 安裝目錄,然后再輸入如下的命令


    $cd $NDK

注意:輸入 cd $NDK 后,會(huì)自動(dòng)跳到你設(shè)置的 ndk 的目錄中

$make APP=

$make APP= -B 表示重新編譯

結(jié)果跟第一種方法一樣,除了中間文件被放置到了 $NDK/out/apps//

4. 從新 build 你的應(yīng)用程序包

在 NDK 生成的二進(jìn)制文件后,你需要使用一般的方法來(lái)重新 build 你的 Android 應(yīng)用程序包文件(apk),或者用“ant”命令或者 ADT 插件

有關(guān)詳細(xì)信息,請(qǐng)參閱 Android SDK 的文檔,新的.apk 會(huì)嵌入到您的共享庫(kù)中,他們將自動(dòng)提取安裝時(shí)由系統(tǒng)安裝的軟件包到你的 Android 設(shè)備上

5. 調(diào)試支持

NDK 提供了一個(gè)服務(wù)腳本,名字叫”ndk-gdb”,很容易推出一個(gè)應(yīng)用程序的本地調(diào)試會(huì)話。

本機(jī)調(diào)試僅僅能運(yùn)行在 Android 2.2 或者更高版本,并且不需要 root 權(quán)限或者特權(quán)訪問(wèn),所以可以隨意調(diào)試你的應(yīng)用程序。

有關(guān)詳細(xì)信息,請(qǐng)閱讀 DOCS / NDK- GDB.html??偫ǘ?,本機(jī)調(diào)試 遵循這個(gè)簡(jiǎn)單的計(jì)劃:
(1)確保您的應(yīng)用程序調(diào)試(如設(shè)置機(jī)器人:調(diào)試“真”,在您的 AndroidManifest.xml)

(2) “NDK 構(gòu)建”構(gòu)建您的應(yīng)用程序,然后安裝在您的 設(shè)備/模擬器

(3)啟動(dòng)應(yīng)用程序。

(4)運(yùn)行“ndk-gdb”從你的應(yīng)用程序項(xiàng)目目錄。

你會(huì)得到一個(gè) gdb 提示符。一個(gè)有用的列表,請(qǐng)參閱 GDB 用戶手冊(cè)命令。

上一篇:安裝 NDK下一篇:調(diào)試