介紹:
Android SDK是一個允許Android應用開發人員使用C或C++源檔案編譯並嵌入到本機原始碼中的應用程式套件組合的一組工具。
重要說明:
Android NDK只能用於android 1.5以上版本
<!--[if !supportLists]-->1. <!--[endif]-->Android NDK的目的:
Android虛擬機器允許你的應用程式原始碼通過JNI調用在本地實現的原始碼,簡單的說,這就意味著:
----你的應用程式將聲明一個或多個用’native’關鍵字的方法用來指明它們是通過本地代碼實現的
例如:native byte[] loadFile(String filePath)
----你必須提供包含實現這些方法的共用庫(就是.so),將共用庫打包到你的應用程式套件組合apk中,這些庫檔案必鬚根據標準的Unix約定來命名為 lib<something>.so,並且是需要包含一個標準的JNI的介面,例如
libFileLoader.so
----你的應用程式必須明確的裝載這些庫檔案(.so檔案),比如,在程式的開始裝載它,只需要簡單的添加幾句原始碼:
static {
System.loadLibrary(“FileLoader”);
}
注意:這裡你不必再將首碼lib和尾碼.so寫入。
Android NDK對於Android SDK只是個組件,它可以幫你:
----產生的JNI相容的共用庫可以在大於Android1.5平台的ARM CPU上運行
----將產生的共用庫拷貝到合適的程式工程路徑的位置上,以保證它們自動的添加到你的apk包中(並且簽名的)
----在以後的版本中,我們將提供來協助你的原始碼通過遠程gdb串連和儘可能多的原始碼的資訊。
而且,Android NDK還提供:
----一組交叉編譯鏈(編譯器、連結器等)來產生可以在Linux,OS X和Windows(用Cygwin)啟動並執行二進位檔案
----一組與由Android平台提供的穩定的本地API列表的標頭檔
它們在docs/STABLE-APIS.html中有說明
重要提示:
記住,在以後的更新和發布平台中,Android系統鏡像中的大多數本地系統庫並不是一成不變的,而是可以徹底改變,甚至刪除的
----一個編譯系統(build system)可以允許開發人員寫一個非常短的編譯檔案(build files)去描述哪個原始碼需要編譯,並且怎樣編譯。編譯系統可以解決所有的toolchain/platform/CPU/ABI細節的問題。並且,較晚的NDK版本中還添加了更多的可以不用改變開發人員的編譯檔案的情況下的toolchains,platforms,系統介面
<!--[if !supportLists]-->2. <!--[endif]-->Android NDK的缺點
NDK並不是一個可以編寫通用的原始碼並且可以在Android裝置上啟動並執行方法,你的應用程式還是需要使用JAVA程式,適當的處理系統事件來避免“應用程式沒有反應”的對話方塊或者處理Android應用程式的生命週期
注意:可以適當的在原始碼中寫一個複雜的應用程式,用於啟動/停止一個小型的“應用程式套件組合”
強烈建議很好地理解的 JNI,因為許多操作在這種環境要求的開發人員,都採取具體的行動,不一定在常見典型的機器碼。這些措施包括:
----不能通過指標直接存取VM的對象。比如:你不能安全的得到一個指向String對象的16位char數組的迴圈遍曆
----需要顯示引用管理機器碼時候要保持處理JNI調用之間的VM對象
NDK在Android平台僅僅提供了有限的本地API和庫檔案的支援的系統標頭檔,然而一個標準的Android系統鏡像包括許多本地共用庫,這些都應該被考慮在更新和發行版本的可以徹底改變的實現細節
如果Android系統庫沒有明確的被NDK明確的支援,然後應用程式不應該依賴於它提供的,或者打破了將來在各種裝置上的無線系統更新
選定的系統庫將逐漸被添加到穩定的NDK API中
<!--[if !supportLists]-->3. <!--[endif]-->NDK開發實踐
下面將給出一個怎樣用Android NDK開發本地代碼的粗略的概述
<!--[if !supportLists]-->(1) <!--[endif]-->把本地代碼放在$PROJECT/jni/…下,比如將hello.c放到apps/hello/jni/目錄下
<!--[if !supportLists]-->(2) <!--[endif]-->在你的NDK編譯系統中在$PROJECT/jni/Android.mk來描述你的原始碼
<!--[if !supportLists]-->(3) <!--[endif]-->可選:在$PROJECT/jni/Application.mk到你的編譯系統中來詳細描述你的項目,儘管你開始的話不一定需要它,但是它允許你使用更多的CPU或者覆蓋編譯器/連結器 的標記(看docs/APPLICATION-MK.html瞭解更多細節)
<!--[if !supportLists]-->(4) <!--[endif]-->從你的項目的目錄開始通過運行”$NDK/ndk-build”來編譯你的代碼,或者從子目錄開始
<!--[if !supportLists]-->(5) <!--[endif]-->最後一步可以copy,萬一成功,剝離共用庫的應用程式層序需要你的應用程式的項目根目錄。然後你通過通常的方法來產生最終的apk
現在,開始一些更詳細的細節
<!--[if !supportLists]-->① <!--[endif]-->配置NDK
以前的發行版本需要你運行“build/host-setup.sh”指令碼來配置你的NDK。從release 4(NDK r)以後就完全去除了這一步
<!--[if !supportLists]-->② <!--[endif]-->放置C/C++代碼
假如我們建立的是test目錄,建立的代碼hello.c
把hello.c放到test/jni目錄下
這個項目的位置相當於你的Android應用程式項目的路徑
這樣你就很輕鬆的組織起來了你想要的jni的目錄,這裡項目目錄的名字和結構不會影響到最終產生的apk,所以你不必用類似於com.<mycompany>.<myproject>作為應用程式套件組合名
注意,NDK是支援C和C++的,NDK支援的C++副檔名是’.cpp’,但是其他的副檔名也是可以被處理的(看docs/ANDROID-MK.html瞭解更多)
它可以通過調整你的Android.mk檔案來將原始碼放在不同的位置
<!--[if !supportLists]-->③ <!--[endif]-->建立一個Android.mk編譯指令碼
Android.mk檔案是一個小型的編譯指令碼,你可以在NDK編譯系統中用它來描述你的原始碼。更詳細的描述在docs/ANDROID-MK.html中
總而言之,NDK將你的原始碼彙總到模組(modules)中,每個模組可以執行下列之一
----一個靜態庫(lib<project>.a)
----一個動態庫(lib<project>.so)
你可以在Android.mk中定義多個模組,或者你可以編寫多個Android.mk檔案,每一個定義一個單獨的模組
注意,單獨的Android.mk也行被編譯系統多次解析,以確定哪些變數沒有被定義。
預設地,NDK會通過如下的編譯指令碼去尋找
test/jni/Android.mk(存放位置)
如果你想定義Android.mk到子目錄中,你需要在最高層的Android.mk中明確的包含它們,下面是一個協助的方法可以實現這個功能。
include $(call all-subdir-makefiles)
它會將所有的在子目錄中的Android.mk檔案加入到當前編譯檔案的路徑中
<!--[if !supportLists]-->④ <!--[endif]-->寫一個Application.mk編譯檔案(可選)
在你的編譯系統中有一個Android.mk檔案描述模組的同時,Application.mk檔案藐視你的應用程式本身。請看docs/APPLICATION-MK.html文檔來理解這個檔案允許我們做什麼。這包括
----你的應用程式需要模組的準確清單
----CPU架構產生機器代碼
----可選資訊,你是否需要一個release或者debug build,特殊的C/C++編譯器標誌和其他適用於所有模組的build
這個檔案是可選檔案:預設地,NDK會提供一個對於所有的在你的Android.mk(所有的makefiles都在裡面)中的所有模組的簡單編譯並且指定預設的CPU ABI
使用Application.mk有兩種方法:
----把它放到 test/jni/Application.mk,它就會自動的被’ndk-build’指令碼找出來
----把它放在NDK/<name>/Application.mk,也就是NDK安裝的路徑下,然後從NDK目錄下執行”make APP=<name>”
這個方法是Android NDK r4以前的。現在仍然相容。但是我們強烈建議你使用第一種方法,因為它更簡單並且不用修改NDK安裝樹的目錄。
再次看看docs/APPLICATION-MK.html對於它的完整說明
<!--[if !supportLists]-->⑤ <!--[endif]-->調用NDK編譯系統
用NDK編譯成機器碼的最好方法是使用”ndk-build”指令碼,你還可以使用第二個,這取決於你早起常見的”$NDK/apps”子目錄
在兩種情況下,成功構建將copy應用程式所需的最終的已經剝離的二進位模組(即共用庫)到應用程式的項目路徑中(注意,未剝離的版本主要是用於調試目的,無需拷貝未剝離的二進位檔案到裝置中)
[1]:使用’ndk-build’命令
‘ndk-build’指令碼位於NDK安裝目錄最頂層,可以直接被應用程式項目目錄(你的AndroidManifest.xml檔案所在位置)或者其他任何子目錄
$cd $PROJECT
$NDK/ndk-build
這將啟動NDK的build指令碼,它會自動探測您開發的系統和應用程式專案檔,以確定build設麼
例如:
$ndk-build
$ndk-build clean à清理產生的二進位檔案
$ndk-build –B V=1 à強制完全重新build,顯示命令
預設的,它期望的是可選檔案 $PROJECT/jni/Application.mk和必須的檔案$PROJECT/jni/Android.mk
成功的話,它講話就複製產生的二進位模組(即共用庫.so檔案)到你的項目樹中的適當位置。您可以在以後重新build完整的Android應用程式套件組合或者通過“ant”命令,或者ADT外掛程式。
可以看docs/NDK-BUILD.html來瞭解更多的資訊
[2]:使用$NDK/apps/<name>/Application.mk
這種build方法是在Android NDK r4版本之前的,不過依然相容現在的。我們強烈建議您儘可能的使用’ndk-build’,因為我們可能會刪除在以後的NDK發行版本中的支援
<!--[if !supportLists]-->① <!--[endif]-->建立一個子目錄為$NDK/apps/<name>/
<!--[if !supportLists]-->② <!--[endif]-->在$NDK/apps/<name>/目錄下寫一個Application.mk檔案,然後需要定義一個APP_PROJECT_PATH來執行你的應用程式項目的目錄。
<!--[if !supportLists]-->③ <!--[endif]-->進入到NDK安裝目錄,然後再輸入如下的命令
$cd $NDK
$make APP=<name>
或
$make APP=<name> -B 表示重新編譯
結果跟第一種方法一樣,除了中間檔案被放置到了$NDK/out/apps/<name>/
<!--[if !supportLists]-->4. <!--[endif]-->從新build你的應用程式套件組合
在NDK產生的二進位檔案後,你需要使用一般的方法來重新build你的Android應用程式套件組合檔案(apk),或者用“ant”命令或者ADT外掛程式
有關詳細資料,請參閱Android SDK的文檔,新的.apk會嵌入到您的共用庫中,他們將自動提取安裝時由系統安裝的軟體包到你的Android裝置上
<!--[if !supportLists]-->5. <!--[endif]-->調試支援
NDK提供了一個服務指令碼,名字叫”ndk-gdb”,很容易推出一個應用程式的本地偵錯工作階段。
本機調試僅僅能運行在Android 2.2或者更高版本,並且不需要root許可權或者特權訪問,所以可以隨意調試你的應用程式。
有關詳細資料,請閱讀DOCS / NDK- GDB.html。總括而言,本機調試
遵循這個簡單的計劃:
(1)確保您的應用程式調試(如設定機器人:調試“真”,在您的AndroidManifest.xml)
(2) “NDK構建”構建您的應用程式,然後安裝在您的 裝置/模擬器
(3)啟動應用程式。
(4)運行“ndk-gdb”從你的應用程式項目目錄。
你會得到一個gdb提示符。一個有用的列表,請參閱GDB使用者手冊命令。