Android NDK 概述(Android NDK Overview)

Android NDK 功能概述

Android NDK就是一套用於把C/C++源碼編譯得到的二進制機器碼嵌入應用安裝包的工具。

Android NDK是對Android SDK的一個補充,可以幫助你:

1)生成符合JNI規範的共享庫(運行在Android 1.5以上系統,主要是ARM CPU)

2)將共享庫拷貝到工程合適位置(拷貝之後,在生成apk時,該共享庫自動打包進最終的apk文件)。

3)將來的NDK版本,會提供調試本地碼的工具(利用gdb連接和大量源碼及符號信息)。

Android NDK提供了

1)一套交叉編譯工具鏈(編譯器、鏈接器等),可在Linux, OS X和Windows(通過 Cygwin)系統上直接編譯出ARM代碼。

2)一套系統頭文件。這些頭文件對應Android平臺的穩定API(見Android Stable APIs)。所謂穩定API,就是今後更高版本的Android系統都會支持的API。

3)一個編譯系統。開發人員只需編寫很短的編譯腳本文件,描述哪些源碼文件需要編譯,如何編譯。該編譯系統能處理繁瑣的工具鏈/平臺/CPU/ABI 等細節。今後版本的NDK將支持更多工具鏈、平臺、系統接口,而不用修改編譯腳本。

注意事項:

1)Android NDK只能用於Cupcake以後(即Android 1.5 以後)。尤其是1.0和1.1版Android,NDK完全不支持(因爲ABI和工具鏈有一些修改,導致了不兼容)。

2)Android系統除穩定API,還自帶很多共享庫,但大部分都是可變的,今後有可能做修改。使用非穩定的API,在系統更新之後,程序可能無法工作。

I. Android NDK的目標

Android 虛擬機支持通過JNI調用本地碼實現的函數(本地碼就是C/C++編寫,在不同平臺上編譯得到的機器指令。對arm而言,就是arm指令;對x86而言,就是x86指令)。這意味着:

1)你在用java開發Android應用時,可以用native關鍵字,聲明相應方法是在本地碼中實現的。例如:

    native byte[] loadFile(String filePath);

2)對於這些native方法,你必須提供一個共享庫(*.so文件),包含這些方法的實現。這個共享庫將來會打包進apk。這個共享庫必須按照UNIX共享庫的命名規則命名,例如:

        lib<something>.so

    它還必須包含一個標準的JNI入口函數。

3)java程序在使用這些native方法之前,必須加載該共享庫。例如,下面代碼是在啓動的時候加載:

    static {

        System.loadLibrary("FileLoader");   // 這裏應該取共享庫文件名中間部分,不含“lib”前綴和“.so”後綴。

    }

II. Android NDK不能完成的事情

用NDK開發一個一般化程序不是好方法,應該儘量用Java開發,處理各種Android系統事件和Android程序生命週期。

不過,你可以利用NDK來編寫一個程序(大部分是C/C++),然後用一個小的啓動器(Java)來加載。

對JNI有一程度的瞭解,能夠幫助你更好地使用NDK。

NDK其實只提供了Android系統庫的少數有限API,更多API因爲可能修改所以沒有在NDK中提供(因此找不到相應的頭文件)。

III. NDK開發步驟

這裏初步描述一下如何使用Android NDK進行開發:

1)將源碼文件放在 $PROJECT/jni/...

2)編寫 $PROJECT/jni/Android.mk 文件(編譯腳本,供Android NDK編譯系統使用)

3)可選:編寫 $PROJECT/jni/Application.mk (供Android NDK編譯系統使用。非必須。

可以用來支持更多的CPU平臺,或用來修改編譯器參數)。

4)進入工程根目錄之後,運行ndk-build,完成編譯。編譯完成後,會自動拷貝strip過的共享庫

到工程的根目錄。然後,通過正常步驟來生成最終的apk文件。


上面步驟更詳細的描述如下:

III.1 配置 NDK: 老版本NDK需要運行 build/host-setup.sh 腳本(配置NDK)。NDK r4之後(含r4),不需要該步驟。

III.2 拷貝C/C++文件到jni目錄:  將 C/C++ 文件拷貝到 $PROJECT/jni/ 。該目錄下的文件結構任意,不影響最終的apk。

    C++代碼的默認文件擴展名爲cpp,其他擴展名也可以(見 android-mk )。 也可以把源碼放到其他地方,只要在Android.mk中寫明即可。

III.3 編寫 Android.mk:  該文件有自己的語法(見android-mk)。NDK是把那些C/C++代碼文件看做不同的“模塊”,每個模塊可以是一個靜態庫,也可以是一個動態庫。在一個Android.mk文件中可以定義多個模塊。也可以爲每個模塊寫一個android.mk。

注意:同一個Android.mk可能被Android編譯系統解析多次,所以要注意前面的環境變量對後面的影響。

默認情況下,NDK會尋找 $PROJECT/jni/Android.mk 文件。如果jni目錄下還有子目錄,可以在這些子目錄中創建Android.mk,然後在最頂層的Android.mk文件中把這些Android.mk包含進來。有一個輔助函數(將把jni目錄下所有的Android.mk包含進來):

include $(call all-subdir-makefiles)

III.4 編寫 Application.mk(可選): Application.mk描述程序自身,而Android.mk描述模塊如何編譯。Application.mk提供很多功能,一些重要功能如下:

1)列出你的程序必需的模塊   2)指定CPU架構   3)可選信息:例如想要release還是debug版本,C/C++編譯器標誌等全局性信息。

該文件是可選的,如果你沒有提供,則編譯系統用默認的Application.mk(將Android.mk文件中描述的模塊全部編譯,默認CPU爲armeabi)

使用Application.mk的兩種方法:

1)放在 $PROJECT/jni/Application.mk ,會被ndk-build腳本自動檢測。

2)放在 $NDK/apps/<name>/Application.mk,進入NDK所在目錄,執行 make APP=<name> 來完成編譯。

以上第2)種方法用於NDK r4以前,現在依然支持(兼容)。 建議用方法1),因爲它更簡單,且不需要修改NDK安裝目錄。

III.5 調用NDK編譯系統

調用的方式有2種:1)直接執行 ndk-build (更好) 2)在 $NDK/apps 下新建一個子目錄的方法(老方法)

這兩種方法編譯成功後,將把strip過的二進制模塊(即共享庫)拷貝到工程目錄(沒有strip的模塊也會保留,用於調試)。

1)用 ndk-build 命令

ndk-build腳本位於NDK的根目錄,可以在進入工程目錄之後調用(工程目錄就是你的Android工程中,AndroidManifest.xml文件所在的目錄)。

例如:

        $cd /home/wuxiao/workspace/NotePad  (NotePad 是用eclipse創建的)

        $ndk-build

        $ndk-build clean         相當於 make clean

        $ndk-build -B V=1        -B 是強制重新編譯,  V=1 表示打印詳細信息

編譯出二進制代碼後,按普通Android的app的步驟,生成apk。此時共享庫已拷貝到工程的根目錄,

所以這個共享庫會進入apk。

2)老方法:用 $NDK/apps/<name>/Application.mk 方式(爲了兼容而保留,即將被刪除,此處省略)

IV. 編譯生成apk

用NDK生成二進制模塊後,按正常步驟編譯生成apk(可用ant或ADT,在Android SDK文檔中講解)。

生成的apk包含該共享庫。用戶在安裝該apk的時候,共享庫會被系統自動提取。

V. 調試該共享庫

NDK提供了一個ndk-gdb,運行後開啓一個調試會話,連接到你的應用程序。

這種本地碼調試只能在Android 2.2以上系統應用,不需要root權限或其他特權,只需要開啓調試。

大致步驟如下(詳細步驟見文檔 NDK-BUILD):

1)在 AndroidManifest.xml 中設置調試功能爲開啓(將 android:debuggable 設置爲 true)。

2)用 ndk-build 編譯共享庫,生成apk,安裝apk

3)啓動該程序

4)cd進入工程目錄,執行 ndk-gdb,就進入了gdb命令行。

發佈了68 篇原創文章 · 獲贊 5 · 訪問量 41萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章