android中jni的作用,就是讓java能夠去調用由c/c++實作的代碼,為了實作這個功能,需要用到anrdoid提供的ndk工具包,在這裡不講如何配置了,好麻煩,配置了好久。。。
本質上,java去調用c/c++的代碼其實就是去調用c/c++提供的方法,是以,第一步,我們要建立一個類,并且定義一個native方法,如下:
jnitest類:
可以看到,在這個方法的前面,用到了native關鍵字。
接着,我們要在指令行中編譯這個java檔案,得到一個class檔案,如下:
然後我們可以利用javah指令檔案,生成一個c的頭檔案,其實javah這一步不是必需的,因為建立這個頭檔案,隻是為了友善我們複制這個jni中對應的方法名稱,因為這些名稱實在太複雜了。
在這裡有一點要注意,javah指令要在包的根目錄下調用,對應的類檔案,必須是完整的類名,如上圖所示,會先回到src目錄,再調用javah指令。
這樣我們就會在src檔案夾下在産生一個頭檔案,如下圖所示:
我們可以看到其名稱是com_lms_jni_jnitest.h,其實就是包名+類名,我們可以看看裡面的内容:
我們可以看到,在這裡面有一個方法,名稱是java_com_lms_jni_jnitest_getteststring,夠複雜吧,其實如果我們知道這個名稱規則,并且知道如何去實作這樣一個方法的話,我們是完全可以不生成這個頭檔案的,我們可以直接寫出對應的c檔案。
接下來,在jni檔案中建立一個對應的c檔案,名稱是值得并無所謂,但為了統一,我們就把它叫jnitest.c吧,如下:
在這裡,我們也把com_lms_jni_jnitest.h也放到這裡了,這個其實是沒關系的,隻是為了内容的協調和統一而已,一般情況下,我們會把是以由c/c++實作的檔案都放在項目目錄下一個叫 jni 的檔案夾下面。
下面是在jnitest.c中實作native方法,getteststring,如下:
在這個c檔案中,我們看到,并沒有引用頭檔案com_lms_jni_jnitest.h,而隻是引用了一般的c/c++庫檔案,比如stido.h和stdlib.h檔案等,在這裡注意到一點,我們還會引用jni.h檔案,jni.h檔案是jni程式設計中很重要的一個頭檔案,關于java中的資料類型跟jni中的資料類型的對應全部是在這個檔案中定義的,後續會來看一下這個jni.h檔案。
在上面jnitest.c檔案中實作了方法之後,關于c/c++這邊的實作其實也就實作了,那麼接下來就是要将這個c檔案編譯成so檔案由android來調用。
為什麼是so檔案呢,這是因為android本質上就是一個linux系統,是以其調用的jni庫檔案,都是so形式。
android提供的ndk庫提供了ndk-build的指令來實作這個編譯過程,但在此之前,我們要先建立一個android.mk檔案,這是一個簡單的小小的make檔案,其内容如下:
在這裡,我們會定義幾個變量:
local_path:其值是call my-dir,而my-dir是個宏函數,會傳回android.mk所在的路徑,在這裡,就是jni檔案夾。
include $(clear_vars),這個指令會清除掉所有local開頭的變量,比如local_module之類的,但有一個例外,就是其上面的local_path 。
local_module:要生成的so包名,也是android中java代碼加載時的名稱。
local_src_files:要進行編譯的源檔案,如在這裡,有hwdemo.c和jnitest.c等。
include $(build_shared_library):表明生成一個動态連結庫。
定義後這樣一個android.mk檔案之後,在指令行中調用ndk-build指令,如下:
指令實行之後,我們可以在項目目錄下看到libs中多了一個so庫,如下:
到這裡,關于jni實作的就結束了,接下來就是如何在android中使用這個本地方法了。
我們建立了一個activity,在它裡面隻放置一個textview控件,它的布局如下:
然後在activity中,我們要加載這個so庫,如下:
1)利用static靜态代碼塊,加載so庫檔案,可以看到在這裡,這個名稱就是anrdoid.mk中定義的local_module值。
2)建立jnitest對象,調用其getteststring()方法,最終顯示結果如下:
到這裡,通過一個簡單的例子,我們明白了如何在android中利用jni來調用c/c++的方法了。
最後,我們總結一下這幾個步驟:
1)建立java類檔案,并定義native方法,如jnitest類。
2)利用javac生成class檔案,然後回到src目錄,利用javah生成c/c++頭檔案,在這裡要注意,javah指令要在包的根目錄下調用,對應的類檔案,必須是完整的類名,如下:
在src目錄:javah com.lms.jni.jnitest,在上面的截圖,也可以看到javac之後,是回到src目錄,再調用javah。
3)編寫對應的c檔案,如jnitest.c,在裡面實作c/c++的方法,記得要放在jni檔案夾下面。
4)編寫android.mk檔案,利用ndk-build指令生成so檔案。
5)在android中利用static靜态代碼塊,調用system.loadlibrary方法來加載so庫檔案。
6)在java邏輯中調用之前定義的jnitest類的方法。
結束。!