這段時(shí)間因?yàn)殚_(kāi)始編寫(xiě)與硬件結(jié)合的一個(gè)軟件項(xiàng)目,使用到了大量的jni調(diào)用,這里總結(jié)一下使用要點(diǎn)
首先開(kāi)始我們的環(huán)境搭建,Android studio的環(huán)境搭建還是比較簡(jiǎn)單的,在Sdk Manager里找到NDK并安裝,安裝好的NDk一般位于你的sdk文件夾下的ndk-bundle,然后將該路徑配置到你系統(tǒng)變量的path里面去
cmd命令輸入
ndk build
如果未提示"ndk-build不是系統(tǒng)命令"就表示NDK環(huán)境配置完成了!
對(duì)于app來(lái)說(shuō),一些對(duì)圖片的處理、視頻的處理等等需要復(fù)雜算法支持的功能,很多都會(huì)選擇用C語(yǔ)言寫(xiě)成,然后APP端去調(diào)用C語(yǔ)言方法,得到經(jīng)過(guò)算法處理之后的結(jié)果,jni就是Java和C之間調(diào)用的橋梁
在前端時(shí)間的項(xiàng)目中,因?yàn)樾枰罅康氖褂妙?lèi)似活體檢測(cè)、人臉校準(zhǔn)之類(lèi)的算法,所以必不可少的接觸到了jni的使用
Android studio2.2.3之前的jni調(diào)用(此處舉例)
在Java的demo里編寫(xiě)如下代碼
public class MainActivity extends Activity {
static {
System.loadLibrary("JniTest");
}
public native String getStringFromNative();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getStringFromNative();
}
}
此處根據(jù)你寫(xiě)的native的方法名等下生成C語(yǔ)言的.h頭文件
在app文件夾下的build.gradle文件里面配置Ndk相關(guān)信息
ndk {
moduleName "JniTest"
ldLibs "log", "z", "m"
abiFilters "armeabi", "armeabi-v7a", "x86"
}
基本看代碼可以看懂,指定加載so庫(kù)的名稱(chēng)為JniTest,這個(gè)只是為了舉例取的名稱(chēng),加載的abi平臺(tái)為armeabi、armeabi-v7a和x86
sourceSets{
main{
jniLibs.srcDirs = ['libs']
}
}
指定加載so庫(kù)的路徑為libs
生成需要的.h頭文件
在Android Studio下方的Terminal命令行里面執(zhí)行生成命令,如果沒(méi)有Terminal,到"View->Tool Windows->Terminal"里面打開(kāi)該面板
操作命令:
javah -d jni -classpath <SDK_android.jar>;<dir path> 加載So所在的class包名+class名
后面的 “dir path” 加載So所在的class包名+class名 是相對(duì)于你當(dāng)前所在目錄的路徑;
參考命令:
C:\git_source\demo\JniTest>javah -d jni -classpath C:\studio\android-sdk-windows\platforms\android-23\android.jar;app\src\main\java com.example.jni.jnitest.MainActivity
這里的后面一部分是相對(duì)于"C:\git_source\demo\JniTest"目錄的路徑
注意:很多人寫(xiě)命令行的時(shí)候容易寫(xiě)錯(cuò),app\src\main\java后面是空格 接 包名.類(lèi)名
命令執(zhí)行成功會(huì)自動(dòng)生成一個(gè)jni文件夾和對(duì)應(yīng)的"包名.h"文件,這里的文件名是:com_example_jni_jnitest_MainActivity.h

.h文件中的代碼如下
JNIEXPORT jstring JNICALL Java_com_example_jni_jnitest_MainActivity_getStringFromNative(JNIEnv * env, jobject jObj){
return (*env)->NewStringUTF(env,"Hello From JNI!");
}
這里的方法就是根據(jù)你的native方法生成的頭信息,我們來(lái)解析一下意思
JNIEXPORT和JNICALL:jni關(guān)鍵字就跟Java里的關(guān)鍵字一樣
jstring: 方法的返回值為string
Java_com_example_jni_jnitest_MainActivity_getStringFromNative : 格式為Java_+包名_+調(diào)用jni方法的類(lèi)名_+方法名 如果包名里包含下劃線,則用_1代替
接下來(lái)就是編寫(xiě)你的C語(yǔ)言代碼了,如果你不會(huì)寫(xiě)C語(yǔ)言代碼,那就是得有底層給你.cpp的文件或者.C的文件,我們只需要將我們剛剛生成的頭文件里的方法聲明,去替換C語(yǔ)言文件里的方法聲明,這樣C語(yǔ)言的方法就可以被Java調(diào)用了
編輯Android.mk和Application.mk
按照前面第一步的圖里面的jni包里面有一個(gè)Android.mk文件和Application.mk文件,這里我們需要?jiǎng)?chuàng)建這兩個(gè)文件,還有一個(gè)main.c文件就是我們需要生成so庫(kù)的文件,Android.mk文件和Application.mk文件是用來(lái)控制編譯So文件的, Android.mk文件控制So文件如何編譯, Application.mk文件控制支持的架構(gòu)平臺(tái).
Android.mk文件:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#bzlib模塊
bzlib_files := \
main.c
LOCAL_MODULE := libbz
LOCAL_SRC_FILES := $(bzlib_files)
include $(BUILD_STATIC_LIBRARY)
#bspath模塊
include $(CLEAR_VARS)
LOCAL_MODULE := main
LOCAL_SRC_FILES := main.c
LOCAL_STATIC_LIBRARIES := libbz #引入libbz庫(kù)
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := JniTest
LOCAL_SRC_FILES := main.c
LOCAL_STATIC_LIBRARIES := main
LOCAL_LDLIBS := -llog#加入log
include $(BUILD_SHARED_LIBRARY)
"bzlib_files :"里面放的是所有的c源文件;"LOCAL_MODULE := JniTest"表示生成的So庫(kù)名,因?yàn)槲壹虞dSo庫(kù)的名字是"JniTest"所以這里需要同名;
static {
System.loadLibrary("JniTest");
}
Application.mk文件:
APP_CFLAGS += -Wno-error=format-security
APP_ABI := armeabi
APP_ABI := armeabi 表示只支持armeabi架構(gòu)的Jni,如需添加其他架構(gòu)可在后面追加
最后一步:生成.so文件
在CMD命令行里面cd到項(xiàng)目的目錄下, 輸入"ndk-build"生成So包

命令執(zhí)行成功后在工程的libs文件夾下面生成一個(gè)So文件,如下:

如果不添加Application.mk文件,會(huì)生成所有架構(gòu)的So文件,如下:

編譯出來(lái)的So默認(rèn)是放在工程里面的libs文件夾下的,需要將它移到app文件夾下的libs里面!
2.2.3之后的Jni調(diào)用
從AndroidStudio2.2開(kāi)始,studio可以利用NDK直接編譯C/C++代碼。AndroidStudio 支持Cmake和NDK-BUILD 工具編譯本地代碼,但是默認(rèn)方式為Cmake。
在用AndroidStudio開(kāi)發(fā)native應(yīng)用之前先要下載好NDK,Cmake,LLDB(本地代碼調(diào)試工具),可以直接通過(guò)studio的SDK Manager進(jìn)行安裝,安裝完成如下路所示:

創(chuàng)建可以編譯C/C++的工程

直接選擇next,其他跟普通工程無(wú)異,直到Customize C++ support 界面,如下圖所示:

- C++ Standard:Toolchain Default 會(huì)使用默認(rèn)的 CMake 設(shè)置。
- Exceptions Support:對(duì) C++ 異常處理的支持,如果啟用此復(fù)選框,Android Studio 會(huì)將 -fexceptions 標(biāo)志添加到模塊級(jí) build.gradle 文件的 cppFlags 中,Gradle 會(huì)將其傳遞到 CMake。
- Runtime Type Information Support:如果希望支持 RTTI,選中此復(fù)選框,Android Studio 會(huì)將 -frtti 標(biāo)志添加到模塊級(jí) build.gradle 文件的 cppFlags 中,Gradle 會(huì)將其傳遞到 CMake。
選擇好后,最后點(diǎn)擊Finish
稍等片刻,簡(jiǎn)直不敢相信自己的眼睛,簡(jiǎn)直辣眼睛,自動(dòng)生成項(xiàng)目結(jié)構(gòu)如下如所示:

所有的模板已經(jīng)生成好了,只需要往里面填代碼即可!無(wú)需生成.so庫(kù),直接可以調(diào)用jni方法,studio編譯會(huì)自動(dòng)生成.so庫(kù),大大簡(jiǎn)化了以前要自己生成.so庫(kù)的過(guò)程!