Android小白成長之初級篇:NDK配置

AndroidNDK Native Development Kit )實際上屬於 JNI Java Native Interface )的一部分, JNI 就是容許 Java 代碼和其餘語言寫的代碼進行交互。 Android 基於 Java 平臺,天然也是支持這個特徵了,所以 Android NDK 就是支持在 Android 平臺上使用 Java 語言調用採用 C/C++ 編譯的庫文件的一系列工具。

1. 下載:
NDK 的下載頁面爲:http://developer.android.com/sdk/ndk/index.html ,當前最新版本爲r8 ,以下圖所示:
peixun_1.PNG
2012-6-20 18:17 上傳
下載附件 (21.93 KB)

前面咱們說過Android SDK支持三種平臺,這裏相應的Android NDK也是分爲三種平臺WindowsLinux Mac OS X。其中Mac OS X 後面的括號中給出Intel。說明僅支持英特爾的硬件平臺,即在英特爾的電腦上安裝的Mac OS X系統才能使用該NDK,早期的蘋果電腦使用的是非英特爾的硬件平臺,因此這個對於蘋果電腦用戶而言須要是注意的。Linux平臺後面的括號中給出x86,說明只支持運行在x86體系上的Linux平臺。固然Windows平臺早期還支持Alpha處理器,後來的版本就只支持x86體系了。鼠標點擊連接後就開始下載相應的版本了。對Windows平臺有特殊情結的可使用Windows版本的NDK,固然須要Linux系統的模擬環境,最經常使用的就是Cygwin。蘋果迷就直接用Mac OS X版本的NDK就好了。大多數用戶,咱們仍是推薦使用Linux平臺的NDK,下面咱們就以Linux平臺的NDK來配置NDK的開發環境。對於Linux環境,Google官方推薦平臺是Ubuntu,咱們這裏用的是CentOS6.2版本,Linux不一樣版本對於開發來講大同小異,下面咱們就以CentOS6.2來進行配置NDK。
php



2.NDK 的目錄結構說明
下載Linux 平臺的NDK 文件解壓縮後看到的目錄結構以下所示:
peixun_2.PNG
2012-6-20 18:25 上傳
下載附件 (11.63 KB)


build :進行編譯時用到的腳本和一些補丁
docs :有關NDK 的相關文檔
platforms :針對不一樣Android 發行版本進行編譯用到的頭文件和庫文件
prebuilt :一些小工具,用於真正編譯前的預處理階段
samples :給出了一些NDK 的例子
sources :一些在編譯過程當中被腳本或其它工具用到的頭文件和庫文件
tests :執行NDK 的自動化測試,確保NDK 正式發佈後可以正常運行

toolchains:具體進行編譯時的工具,包括對三種架構armmipsx86的支持
html



3.NDK 配置
這個版本NDK的配置比較簡單,前面的老版本還須要設置許多環境變量,這個版本不須要設置,直接解壓縮就能夠了。主目錄android-ndk-r8下有一個腳本文件ndk-build,這個就是進行編譯用的腳本程序。固然,若是運行腳本時不想輸入ndk-build的路徑的話能夠將其所在路徑加入到PATH環境變量中,具體的加入方式咱們在前面的「Linux平臺JDK安裝」一文中已經講過,在此就不重複了。要編譯的文件放在一個目錄下,通常就叫jni(也能夠叫別的名字),把這個目錄放在Android工程下,編譯後的庫文件缺省會自動放到Android工程的庫文件目錄libs中。咱們以NDK自帶的例子程序hello-jni爲例,以下圖所示:
peixun_3.PNG
2012-6-20 18:34 上傳
下載附件 (11.5 KB)


在jni的目錄中,包括編譯配置用的腳本文件和C/C++兩種文件,C/C++除了少許遵循JNI規範外,主要實際上都是Linux環境中C/C++編程而已。配置文件主要有兩個:Android.mk和Application.mk。咱們簡單說一下這兩個文件,通常的NDK開發就足夠了,想詳細瞭解的話能夠閱讀NDK中的相關文檔。
hello-jni例子中Android.mk文件爲例,以下圖所示:
peixun_4.PNG
2012-6-20 18:36 上傳
下載附件 (4.34 KB)

上面兩條是相關的參數和環境變量設置,咱們不用管它。LOCAL_MODULE 右邊的hello-jni 是編譯後庫的名字,LOCAL_SRC_FILES 右邊的hello-jni.c C/C++ 源文件的名字,若是有多個源文件,只須要放在後面用空格隔開就好了,不須要把頭文件放進來。最下面的BUILD_SHARED_LIBRARY 表示編譯爲動態庫,若是要編譯爲靜態庫的話就應該是BUILD_STATIC_LIBRARY
文件Application.mk主要是對編譯的補充,以native-plasma例子中的Application.mk爲例,以下圖所示:

APP_ABI 」的右邊指定了所支持的處理器架構,本次版本的NDK 支持arm x86 mips 三種。缺省是按arm 架構編譯。APP_PLATFORM 的右邊指定的是Android 平臺的版本。缺省是按Android SDK 1.5 版本編譯,版本越高所提供的特性也越多,不過能適配的Android SDK 版本也就越少,意味着可以使用該應用的用戶也越少。
固然,NDK既支持C語言環境,也支持C++語言環境,不過對C++的特性支持要少一些,具體能夠看文檔中對C++支持的相關說明。另外在Android.mkApplication.mk中均可以加入對C/C++進行編譯的一些編譯選項,以例子san-angeles中的Android.mk文件爲例,以下圖所示:
peixun_5.PNG
2012-6-20 18:44 上傳
下載附件 (6.94 KB)

和前面的相比,這裏上邊多了LOCAL_CFLAGS,它的右邊就是編譯選項,這個例子中包括兩個ANDROID_NDKDISABLE_IMPORTGL,每一個選項前加上-D做爲標識符。下邊多了LOCAL_LDLIBS,它的右邊是編譯中用到的庫,每一個庫名前加上-l做爲標識符。
java


本版本的NDK 中有多個例子,咱們簡要說明一下這些的例子的具體做用,便於你們對這些例子有一個初步認識,至少知道每一個例子引入的目的。
bitmap-plasma 如何在NDK 中使用bitmap 的例子,早期的NDK 版本不能直接使用bitmap ,後來的版本中增長了對bitmap 的支持。
hello-gl2 NDK 中如何使用OpenGLES 的運用
hello-jni 最基本的NDK 使用方式,經過NDK 獲取字符串而後在Android 應用中顯示出來
hello-neon NDK 中有關neon 的優化
module-exports 多個庫的調用方式。foo 被編譯爲靜態庫,bar 被編譯爲動態庫並調用了庫foo zoo 被編譯爲動態庫並調用了庫bar
native-activity 徹底用NDK 實現整個Android 程序
native-audio NDK 中有關音頻的操做
native-media NDK 中對視頻的操做
native-plasma 徹底用NDK 實現整個Android 程序而且提供了涉及plasma 的優化
san-angeles 移植到Android 平臺的OpenGL ES 的例子
test-libstdc++ C++ 的支持,但並不是支持C++ 的所有特徵

two-libs:兩個庫的使用,first爲靜態庫,second爲動態庫,而且second庫調用first
android


4.C 語言代碼實現:
咱們以NDK開發包中自帶的例子hello-jni來進行演示和說明。進入jni目錄下,運行ndk-build就能夠進行編譯了,以下圖所示:
peixun_6.PNG
2012-6-20 18:55 上傳
下載附件 (73.71 KB)

編譯後獲得庫libhello-jni.so ,以lib 字符做爲前綴,so 做爲後綴。實際在程序加載時要去掉這兩部分,即文件名稱在lib .so 中間的部分爲真正的庫名稱。須要說明的是和libhello-jni.so 文件在一塊兒的還有兩個文件gdb.setup gdbserver ,這兩個是用於NDK 調試的,在最後正式發佈apk 文件時這兩個文件時不須要的。具體NDK 的調試方法,咱們在後面會將,如今在這裏暫時不講。

Eclipse中加載該例子,因爲該例子最開始不是Eclipse項目,須要建立新項目,選擇從源代碼方式建立,以下圖所示:
peixun_7.PNG
2012-6-20 19:02 上傳
下載附件 (54.01 KB)


建立後,以下圖所示:
peixun_8.PNG
2012-6-20 19:03 上傳
下載附件 (122.06 KB)


Jni 目錄下文件hello-jni.c 以下圖所示:
peixun_9.PNG
2012-6-20 19:03 上傳
下載附件 (9.13 KB)


從上面兩幅圖能夠看到,hello-jniJava環境中的類HelloJni中聲明的函數名爲stringFromJNI,前面要用到修飾符native,類HelloJni所在的包名爲com.example.hellojni,須要用函數System.loadLibrary加載liblibhello-jni.so,採用static修飾符確保只加載一次。而後按正常函數使用就好了。而在NDK這邊,即C語言這層,函數命名要遵循Java___函數的命名方式,中間用下劃線_進行鏈接,如上面所示,在包com.example.hellojni中的類HelloJni聲明爲stringFromJNI,則在C/C++文件中定義的函數名爲Java_com_example_hellojni_HelloJni_stringFromJNI,注意區分大小寫。函數能夠傳參數,本例子中沒有傳入參數,只是有返回參數,返回參數的數據類型爲jstring,即Java中的String類型。對於C/C++中與上面的Java環境打交道的數據類型能夠參照JNI,具體可訪問官方網站http:// java.sun.com/docs/books/jni/。對於函數Java_com_example_hellojni_HelloJni_stringFromJNI中的兩個參數envthiz是系統必須的,若是須要輸入參數,必須再增長參數。這個例子運行的結果就是在文本控件(TextView)上面顯示Hello from JNI by C !,以下圖所示:
peixun_10.PNG

5.C++ 語言代碼實現:
咱們對上面的例子 hello-jni 稍微改動,更名爲 hello-jni-ex ,爲了以示區別把類名和包名也稍微修改了一下。 C++ 語言這種方法靈活性更好,固然,具體採用哪種根據本身的喜愛選擇。 Hello-jni-ex 以下圖所示:
peixun_11.PNG
2012-6-20 19:08 上傳
下載附件 (184.74 KB)


程序運行結果以下圖所示:
peixun_13.PNG
2012-6-20 19:09 上傳
下載附件 (25.33 KB)


有關NDK 的實現部分以下圖所示:
peixun_12.PNG
2012-6-20 19:10 上傳
下載附件 (205.04 KB)


函數registerNativeMethods registerNatives ,以及JNI_OnLoad 裏邊的東西,咱們這邊暫時不講述,後面進一步講述NDK 開發時再詳細講述。咱們真正本身定義的NDK 函數是testStringFromJNI ,這個函數名稱不須要和上層Java 類中的native 聲明函數保持一致。須要保持一致的是對應的包名和類名,這個在變量classPathName 中定義了,定義爲:com/example/hellojniex/HelloJniEx 。在JNINativeMethod 類型的數組filterMethods 中創建上層Java 層面函數調用和NDK 層函數之間的映射關係。第一個變量stringFromJNI 爲在Java 層進行調用的函數名稱,第二個變量()Ljava/lang/String; 爲函數的參數和返回值,第三個變量(void*)testStringFromJNI NDK 層函數名稱(實際就是函數指針)。第一個變量和第三個變量都很容易理解,第二個變量理解起來麻煩一些。()中表示的是函數的參數類型,()後面表示的是函數的返回參數類型。例如本例中的()Ljava/lang/String; 就表示沒有參數,返回String 類型。類型說明以下:
字符 Java類型 C類型
V void void
Z jboolean boolean
I jint int
J jlong long
D jdouble double
F jfloat float
B jbyte byte
C jchar char
S jshort short
數組則以"["開始,用兩個字符表示
[I jintArray int[]
[F jfloatArray float[]
[B jbyteArray byte[]
[C jcharArray char[]
[S jshortArray short[]
[D jdoubleArray double[]
[J jlongArray long[]
[Z jbooleanArray boolean[]
上面的都是基本類型。若是Java 函數的參數是class ,則以"L" 開頭,以";" 結尾中間是用"/" 隔開的包及類名。而其對應的C 函數名的參數則爲jobject. 一個例外是String 類,其對應的類爲jstring
Ljava/lang/String;String jstring
Ljava/net/Socket; Socket jobject
若是JAVA 函數位於一個嵌入類,則用$ 做爲類名間的分隔符。
例如 "(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z"


6 .總結:
本次有關 NDK 的配置到此就講完了,看完本文後,用戶應該可以基本掌握 NDK 的配置和開發。對於進一步有關 NDK 的開發,咱們將在後面的高級開發中詳細講解。
相關文章
相關標籤/搜索