JNI ? ?是java語(yǔ)言提供的Java和C/C++相互溝通的機(jī)制贝奇,Java可以通過(guò)JNI調(diào)用本地的C/C++代碼分井,本地的C/C++的代碼也可以調(diào)用java代碼。
JNI 是本地編程接口撤奸,Java和C/C++互相通過(guò)的接口啸驯。Java通過(guò)C/C++使用本地的代碼的一個(gè)關(guān)鍵性原因在于C/C++代碼的高效性。
NDK ?是一系列工具的集合英上。它提供了一系列的工具炭序,幫助開(kāi)發(fā)者快速開(kāi)發(fā)C(或C++)的動(dòng)態(tài)庫(kù),并能自動(dòng)將so和java應(yīng)用一起打包成apk苍日。
這些工具對(duì)開(kāi)發(fā)者的幫助是巨大的惭聂。它集成了交叉編譯器,并提供了相應(yīng)的mk文件隔離CPU相恃、平臺(tái)辜纲、ABI等差異,開(kāi)發(fā)人員只需要簡(jiǎn)單修改mk文件(指出“哪些文件需要編譯”拦耐、“編譯特性要求”等)耕腾,就可以創(chuàng)建出so。它可以自動(dòng)地將so和Java應(yīng)用一起打包揩魂,極大地減輕了開(kāi)發(fā)人員的打包工作幽邓。
Java通過(guò)JNI機(jī)制和C/C++溝通的具體步驟
1、編寫(xiě)包含native本地方法的java類
2火脉、通過(guò)javah工具生成C/C++語(yǔ)言的頭文件
3牵舵、使用C/C++語(yǔ)言實(shí)現(xiàn)頭文件
4、使用交叉編譯工具對(duì)C/C++本地代碼進(jìn)行編譯倦挂,最后通過(guò)鏈接生成*.so可執(zhí)行的C/C++庫(kù)
5畸颅、實(shí)際執(zhí)行Java代碼去和本地的C/C++代碼互相溝通
JNI是Java調(diào)用Native機(jī)制,是Java語(yǔ)言自己的特性全稱為Java Native Interface方援,類似的還有微軟.Net Framework上的p/invoke没炒,可以讓C#或Visual Basic.Net可以調(diào)用C/C++的API,所以說(shuō)JNI和Android沒(méi)有關(guān)系犯戏,在PC上開(kāi)發(fā)Java的應(yīng)用送火,如果運(yùn)行在Windows平臺(tái)使用JNI是是經(jīng)常的,比如說(shuō)讀寫(xiě)Windows的注冊(cè)表先匪。而NDK是Google公司推出的幫助Android開(kāi)發(fā)者通過(guò)C/C++本地語(yǔ)言編寫(xiě)應(yīng)用的開(kāi)發(fā)包种吸,包含了C/C++的頭文件、庫(kù)文件呀非、說(shuō)明文檔和示例代碼坚俗,我們可以理解為Windows Platform SDK一樣镜盯,是純C/C++編寫(xiě)的,但是Android并不支持純C/C++編寫(xiě)的應(yīng)用猖败,同時(shí)NDK提供的庫(kù)和函數(shù)功能很有限速缆,僅僅處理些算法效率敏感的問(wèn)題,所以推薦初學(xué)者學(xué)好Java后再學(xué)習(xí)JNI恩闻。
簡(jiǎn)單點(diǎn)說(shuō)艺糜,用C語(yǔ)言生成一個(gè)庫(kù)文件,在java中調(diào)用這個(gè)庫(kù)文件的函數(shù)判呕。JNI的過(guò)程比較復(fù)雜倦踢,生成.so需要大量操作送滞,而NDK就是簡(jiǎn)化了這個(gè)過(guò)程侠草。
---------------------------------------------------------------------------------------------------------------------------------------
1. 首先創(chuàng)建MainActivity,添加native方法:
2. 在main目錄下創(chuàng)建一個(gè)jni目錄犁嗅,用來(lái)放頭文件边涕,可以用下面的方法:
3. 編譯頭文件
在Terminal中進(jìn)入到項(xiàng)目的根目錄,對(duì)于Android Studio來(lái)說(shuō)褂微,切換到app\src\main就行功蜓,按照網(wǎng)上的說(shuō)法,直接執(zhí)行下面的命令:
javah -d jni com.jackie.hellondk.MainActivity(-d jni 指定頭文件生成在jni目錄下宠蚂,如果沒(méi)有第二步創(chuàng)建jni文件夾式撼,也會(huì)自動(dòng)創(chuàng)建)
很明顯,找不到MainActivity的.class字節(jié)碼文件求厕,然后按照官網(wǎng)的方法著隆,指定MainActivity.class的路徑,在Android Studio中呀癣,所有的.class文件都生成在app\build\intermediates\classes\debug下面美浦,所以,執(zhí)行下面的命令:
javah -classpath ..\..\build\intermediates\classes\debug?-d jni com.jackie.hellondk.MainActivity
這是什么原因呢项栏?這是由于我們上面的MainActivity繼承了AppCompatActivity浦辨,這個(gè)類是在Android v7的兼容包下,所以還需要v7的兼容包加入到classpath中:
javah -classpath D:\DevTools\studio_sdk\extras\android\support\v7\appcompat\libs\android-support-v7-appcompat.jar;..\..\build\intermediates\classes\debug -d jni com.jackie.hellondk.MainActivity
同樣沼沈,也需要將v4的兼容包加入到classpath中:
javah -classpath?D:\DevTools\studio_sdk\extras\android\support\v4\android-support-v4.jar;D:\DevTools\studio_sdk\extras\android\support\v7\appcompat\libs\android-support-v7-appcompat.jar;..\..\build\intermediates\classes\debug -d jni com.jackie.hellondk.MainActivity
無(wú)語(yǔ)了流酬,真是處處都是坑啊,繼續(xù)把a(bǔ)ndroid.jar添加到classpath中唄列另!
javah -classpath D:\DevTools\studio_sdk\platforms\android-23\android.jar;D:\DevTools\studio_sdk\extras\android\support\v4\android-support-v4.jar;D:\DevTools\studio_sdk\extras\android\support\v7\appcompat\libs\android-support-v7-appcompat.jar;..\..\build\intermediates\classes\debug -d jni com.jackie.hellondk.MainActivity終于成功生成了頭文件芽腾,如下:
4. 實(shí)現(xiàn)native方法
在jni目錄新建一個(gè)hello.c文件,實(shí)現(xiàn)頭文件中的方法:
5. 編寫(xiě)Android.mk文件
6. 編譯動(dòng)態(tài)鏈接庫(kù)so访递,注意要切換到j(luò)ni所在的目錄晦嵌,執(zhí)行ndk-build之前,還需要配置環(huán)境變量。
7. 引用
編譯會(huì)出現(xiàn)下面的錯(cuò)誤:
在gradle.properties添加下面一句:
android.useDeprecatedNdk=true
繼續(xù)編譯惭载,錯(cuò)誤如下:
配置如下:
編譯后旱函,安裝完成后,還是會(huì)出現(xiàn)java.lang.UnsatisfiedLinkError?couldn't find libhello.so的錯(cuò)誤描滔。
修改build.gradle配置棒妨,在defaultConfig里面新增一下代碼:
ndk {? ? moduleName"hello"abiFilters"armeabi","armeabi-v7a","x86"}
注意,這里的moduleName一定要和System.loadLibrary以及Android.mk中定義的名稱一致含长。
最后一次運(yùn)行券腔,終于看到了久違的界面啊拘泞!走了很多彎路纷纫,真是處處都是坑,做個(gè)記錄陪腌,希望對(duì)你們有所幫助辱魁。最后說(shuō)一點(diǎn),上面用ndk-build來(lái)編譯生成動(dòng)態(tài)鏈接庫(kù)libhello.so诗鸭,然后在Java中通過(guò)loadLibrary來(lái)加載染簇。在實(shí)際開(kāi)發(fā)過(guò)程中,完全可以省去ndk-build這一步强岸,開(kāi)發(fā)好jni程序后锻弓,直接運(yùn)行程序,Android Studio會(huì)自動(dòng)幫我們編譯動(dòng)態(tài)鏈接庫(kù)蝌箍,親測(cè)成功青灼!