Android JNI詳細開發有圖有真相

JNI是Java Native Interface的縮寫,通過JNI可以方便我們在Android平臺上進行C/C++編程。要用JNI首先必須安裝Android的NDK,配置好NDK環境之後就可以在Eclipse下進行C/C++開發了。

    其實JNI的原理很容易理解,其本質就是在Java層定義一個接口,同時在C層用C/C++代碼實現該接口的功能並編譯成動態鏈接庫,這樣Activity就可以通過Java層接口調用生成的動態鏈接庫,完成相應的功能。簡單地說就是兩點:(1)定義Java接口(JNI),(2)用C/C++實現接口功能並打包成庫文件以供調用。

    在這裏,我將假設讀者已經在Linux環境下安裝好了NDK,並且會使用Eclipse。下面以C++爲例一步一步說明JNI開發過程。

   

1 創建Android工程

    新建一個TestJNI目錄,用Eclipse在該目錄下創建一個名爲TestJNI的Android工程,包名爲com.TestJNI.jni。創建完成後在工程的src目錄下會自動創建一個名爲TestJNIActivity.java的文件。
【筆記】Android平臺下的JNI開發

 

2 設計Java接口
    先不用管這個文件,在該文件的位置再創建一個名爲TestJNI.java文件:

【筆記】Android平臺下的JNI開發

 

打開TestJNI.java,我們將在這個文件裏創建一個JNI接口類,該Java類提供一個加法運算的接口:
【筆記】Android平臺下的JNI開發

這裏的函數聲明一定要加native修飾。

 

3 編譯JNI

    將TestJNI.java文件複製到工程的bin目錄下,在終端中進入該工程的bin目錄,輸入javac TestJNI.java,這時會生成一個TestJNI.class文件。

【筆記】Android平臺下的JNI開發

在bin文件夾下,如果沒有則創建目錄:/com/TestJNI/jni,並把TestJNI.class複製到/bin/com/TestJNI/jni目錄下。然後在終端裏進入工程的bin目錄,輸入javah -jni com.TestJNI.jni.TestJNI,此時會生成一個com_TestJNI_jni_TestJNI.h文件。

【筆記】Android平臺下的JNI開發

com_TestJNI_jni_TestJNI.h文件就是對應於上面定義的Java接口的C/C++頭文件。打開這個文件,可以看到系統已經爲我們自動完成了接口函數的聲明:

【筆記】Android平臺下的JNI開發

這三個函數分別對應於JNI的三個接口函數,命名方式只是在前面加上了Java包名。

 

4 用C/C++實現JNI

    有了JNI的C/C++頭文件,就可以在C層實現JNI接口了。首先在工程目錄下創建一個jni目錄,這個目錄就是專門用來放C/C++代碼的。把com_TestJNI_jni_TestJNI.h文件複製到jni目錄下,並在這裏創建一個com_TestJNI_jni_TestJNI.cpp文件。

    由於我想用C++來實現JNI,所以上面兩個文件我只是用來作爲動態鏈接庫的接口,具體的實現我希望放在一個類裏面來完成,因此我再添加兩個文件:Add.h和Add.cpp。

【筆記】Android平臺下的JNI開發

下面我們就來實現CAdd類和JNI接口。首先實現CAdd類:

Add.h

【筆記】Android平臺下的JNI開發

 

Add.cpp

【筆記】Android平臺下的JNI開發

然後我們來寫com_TestJNI_jni_TestJNI.cpp,實現JNI:

【筆記】Android平臺下的JNI開發


到此我們的C/C++部分就全部實現了。

5 創建mk文件

    JNI實現了之後就要把C/C++代碼編譯成動態鏈接庫.so文件,這樣Java程序才能調用JNI的接口。要編譯so文件,需要寫Android.mk和Application.mk兩個文件。我們先來寫Android.mk。

    先在工程目錄的jni下創建一個Android.mk文件:

【筆記】Android平臺下的JNI開發

然後打開文件在裏面輸入如下內容:

【筆記】Android平臺下的JNI開發

其中LOCAL_PATH是C/C++代碼所在目錄,也就是我們的jni目錄。

LOCAL_MODULE是要編譯的庫的名稱。編譯器會自動在前面加上lib,在後面加上.so。

LOCAL_SRC_FILES是要編譯的C/C++文件。

 

現在我們在工程的根目錄下創建一個Application.mk文件,並輸入如下內容:

【筆記】Android平臺下的JNI開發

6 編譯動態鏈接庫

    寫完了mk文件就可以開始編譯C/C++代碼了。在終端裏進入工程的根目錄,輸入ndk-build即可:

【筆記】Android平臺下的JNI開發

編譯成功後會在工程目錄的libs/armeabi目錄下生成一個libTestJNI.so文件。

 

7 在Java中調用JNI

    大家應該還記得在創建工程的時候就已經生成了一個TestJNIActivity.java文件吧。現在打開這個文件,我們來對它進行一點修改,添加我們調用JNI計算加法的代碼,如下:
【筆記】Android平臺下的JNI開發

在這裏我們首先用System.loadLibrary("TestJNI")加載了C/C++編譯的so文件,然後創建了一個TestJNI對象,通過該對象調用了so庫中的方法。現在的代碼應該是編譯不過去的,因爲我們還沒有給TextView添加ID,所以R.id.tv是無效的。那麼我們來添加這個ID。找到res/layout目錄下的main.xml文件:

【筆記】Android平臺下的JNI開發

 

雙擊打開該文件,在TextView標籤下添加一行android:id="@+id/tv",這樣就創建了一個名爲tv的域並自動分配ID,如下圖:

【筆記】Android平臺下的JNI開發

現在編譯工程,就可以順利通過了。程序運行結果如下:

【筆記】Android平臺下的JNI開發

 

    這個例子只是爲了顯示JNI的用法,只要寫好了JNI接口,其他的編程就跟C/C++一樣了。編譯動態鏈接庫的時候,除了使用ndk-build命令之外,也可以在Eclipse工程中配置一個Builder,直接在Eclipse下編譯。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章