基本概念
JNI
JNI(Java Native Interface)顾腊,Java本地接口斋扰,是為方便java調(diào)用C或者C++等本地代碼所封裝的一層接口谴仙。由于Java的跨平臺(tái)性導(dǎo)致本地交互能力不好陵刹,一些和操作系統(tǒng)相關(guān)的特性Java無(wú)法完成丈攒,于是Java提供了JNI專門(mén)用于和本地代碼交互。
無(wú)論是 Linux,Windows 還是 Mac OS巡验,或者一些匯編語(yǔ)言寫(xiě)的底層硬件驅(qū)動(dòng)都是 C/C++ 寫(xiě)的际插。Java和C/C++不同 ,它不會(huì)直接編譯成平臺(tái)機(jī)器碼显设,而是編譯成虛擬機(jī)可以運(yùn)行的Java字節(jié)碼的.class文件框弛,通過(guò)JIT(Just-In-Time)技術(shù)即時(shí)編譯成本地機(jī)器碼,所以有效率就比不上C/C++代碼捕捂,JNI技術(shù)就解決了這一痛點(diǎn)瑟枫,JNI 可以說(shuō)是 C 語(yǔ)言和 Java 語(yǔ)言交流的適配器、中間件指攒。其實(shí)主要是定義了一些JNI函數(shù)慷妙,讓開(kāi)發(fā)者可以通過(guò)調(diào)用這些函數(shù)實(shí)現(xiàn)Java代碼調(diào)用C/C++的代碼,C/C++的代碼也可以調(diào)用Java的代碼允悦,這樣就可以發(fā)揮各個(gè)語(yǔ)言的特點(diǎn)了膝擂。
NDK
NDK(Native Development Kit),是android提供的一個(gè)工具合集隙弛,幫助開(kāi)發(fā)者快速開(kāi)發(fā)C(或C++)的動(dòng)態(tài)庫(kù)架馋,并能自動(dòng)將.so和java應(yīng)用一起打包成apk。NDK集成了交叉編譯器(交叉編譯器需要UNIX或LINUX系統(tǒng)環(huán)境)全闷,并提供了相應(yīng)的mk文件隔離CPU叉寂、平臺(tái)、ABI等差異总珠,開(kāi)發(fā)人員只需要簡(jiǎn)單修改mk文件(指出“哪些文件需要編譯”屏鳍、“編譯特性要求”等),就可以創(chuàng)建出.so局服。
ABI
ABI(Application binary interface)應(yīng)用程序二進(jìn)制接口钓瞭。不同的CPU 與指令集的每種組合都有定義的 ABI (應(yīng)用程序二進(jìn)制接口),一段程序只有遵循這個(gè)接口規(guī)范才能在該 CPU 上運(yùn)行腌逢,所以同樣的程序代碼為了兼容多個(gè)不同的CPU,需要為不同的 ABI 構(gòu)建不同的庫(kù)文件超埋。當(dāng)然對(duì)于CPU來(lái)說(shuō)搏讶,不同的架構(gòu)并不意味著一定互不兼容。
armeabi設(shè)備只兼容armeabi霍殴;
armeabi-v7a設(shè)備兼容armeabi-v7a媒惕、armeabi;
arm64-v8a設(shè)備兼容arm64-v8a来庭、armeabi-v7a妒蔚、armeabi;
X86設(shè)備兼容X86、armeabi肴盏;
X86_64設(shè)備兼容X86_64科盛、X86、armeabi菜皂;
mips64設(shè)備兼容mips64贞绵、mips;
mips只兼容mips恍飘;
就目前市場(chǎng)份額而言榨崩,絕大部分的設(shè)備都已經(jīng)是armeabi-v7a、arm64-v8a章母,可以考慮只保留armeabi-v7a架構(gòu)的SO文件母蛛,這樣能獲得更好的性能效果。
開(kāi)發(fā)流程
本文根據(jù)版本的不同介紹了兩種在Android Studio中實(shí)現(xiàn)NDK的方法:Android Studio 2.2 以下和2.2以上乳怎。
Android Studio 2.2 以下版本
步驟如下
- 配置Android NDK環(huán)境
- 關(guān)聯(lián)Andorid Studio項(xiàng)目 與NDK
- 創(chuàng)建本地代碼文件(即需要在 Android項(xiàng)目中調(diào)用的本地代碼文件)
- 創(chuàng)建Android.mk文件 & Application.mk文件
- 通過(guò)ndk-build命令編譯上述文件彩郊,生成.so庫(kù)文件,并放入到工程文件中
- 在Andoird Studio項(xiàng)目中使用NDK實(shí)現(xiàn)JNI功能
由于我學(xué)習(xí)的時(shí)候所使用的Android Studio版本已經(jīng)是3.0了舞肆,所以這種方法已經(jīng)失效了焦辅。編譯時(shí)報(bào)錯(cuò)如下:
Error:Execution failed for task ':app:compileDebugNdk'.
> Error: Flag android.useDeprecatedNdk is no longer supported and will be removed in the next version of Android Studio. Please switch to a supported build system.
Consider using CMake or ndk-build integration. For more information, go to:
[https://d.android.com/r/studio-ui/add-native-code.html#ndkCompile](https://d.android.com/r/studio-ui/add-native-code.html#ndkCompile)
To get started, you can use the sample ndk-build script the Android
plugin generated for you at:
C:\Users\peter\MyApp\JNIDemo\app\build\intermediates\ndk\debug\Android.mk
Alternatively, you can use the experimental plugin:
[https://developer.android.com/r/tools/experimental-plugin.html](https://developer.android.com/r/tools/experimental-plugin.html)
To continue using the deprecated NDK compile for another 60 days, set
android.deprecatedNdkCompileLease=1519725194213 in gradle.properties
Android Studio 2.2 以上版本
只需要在Android Studio中的SDK tools中下載Cmake、NDK和LLDB三個(gè)工具椿胯,然后在Android Studio中新建項(xiàng)目的時(shí)候筷登,在向?qū)Ы缑婀催xC++支持選項(xiàng)然后創(chuàng)建項(xiàng)目就可以了。
項(xiàng)目創(chuàng)建好以后我們可以看到和普通Android項(xiàng)目有以下4個(gè)不同哩盲。
- main 下面增加了 cpp 目錄前方,即放置 c/c++ 代碼的地方
- module的 build.gradle 有修改
- 增加了 CMakeLists.txt 文件
- 多了一個(gè) .externalNativeBuild 目錄
詳細(xì)內(nèi)容可以參看Android NDK開(kāi)發(fā)掃盲及最新CMake的編譯使用。
由此可以總結(jié)出使用CMake編程的步驟如下:
- 新建cpp目錄廉油,寫(xiě)好C/C++代碼惠险。
- 創(chuàng)建并配置CMakeLists.txt文件。
- build.gradle文件中根據(jù)情況進(jìn)行配置抒线,CMakeLists.txt文件的路徑必須配置班巩。
- java代碼中即可調(diào)用C/C++代碼,運(yùn)行程序嘶炭。Java中調(diào)用JNI方法需要在具體的類(lèi)中做以下操作:
//1抱慌、加載lib庫(kù)
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
//2、聲明調(diào)用的方法
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
//3眨猎、調(diào)用方法
// Example of a call to a native method
TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(stringFromJNI());
小結(jié)
從一個(gè)小白的視角記錄一下JNI編程需要掌握的基本概念以及自己跑個(gè)Hello world抑进,做個(gè)學(xué)習(xí)筆記,感謝鏈接中作者的無(wú)私奉獻(xiàn)睡陪。如果需要近一步學(xué)習(xí)可以參看JNI學(xué)習(xí)總結(jié)(實(shí)踐篇)寺渗。
參考文獻(xiàn)
- 向您的項(xiàng)目添加 C 和 C++ 代碼(Google官方文檔)
- Android:JNI 與 NDK到底是什么匿情?(含實(shí)例教學(xué))
- Android NDK開(kāi)發(fā)掃盲及最新CMake的編譯使用
- Android Studio 手把手教你NDK打包SO庫(kù)文件,并提供對(duì)應(yīng)API 使用它(賦demo)
- Android 開(kāi)發(fā)藝術(shù)探索——JNI和NDK編程
- Android Studio NDK及so文件開(kāi)發(fā)(一)
- NDK開(kāi)發(fā) 從入門(mén)到放棄(七:Android Studio 2.2 CMAKE 高效NDK開(kāi)發(fā))