其實NDK開發(fā)具體操作在NDK官網(wǎng)Guides中已經(jīng)有了很詳細的介紹汉操。枝恋。這里主要記錄一下我自己的操作過程和遇到的坑
1、準備工作
先配置好AndroidStudio的NDK環(huán)境
- 從NDK官網(wǎng)下載合適的NDK版本
- 下載好NDK開發(fā)包之后解壓到自己指定的目錄中
- 設置AndroidStudio 的NDK路徑,有兩種設置方法
- 可以通過local.properties文件設置
- 也可以通過AndroidStudio來設置
2昔穴、項目配置
添加C/C++ 代碼有兩種情況霹菊,一種是有.so文件剧蚣,第二種是有源碼需要編譯出.so
2.1 已有.so 文件的情況
2.1.1 把.so文件添加到工程路徑app/libs 下對應的CPU架構的文件夾下
2.1.2 然后在build.gradle中配置jni庫的尋找路徑
sourceSets.main { jniLibs.srcDirs = ['libs']}
當然這里就可以指定其他路徑,然后把.so文件放到對應路徑下的CPU架構的文件夾下
注意 之前看一篇文章說libs是AndroidStudio默認的搜索路徑旋廷,所以我就沒到build.gradle中添加配置鸠按,導致jni調用的函數(shù)一直沒有找到而拋出異常。不知道是不是我自己的操作問題饶碘,不過加上配置就都正常了
2.2 有源碼目尖,需要編譯出.so
編譯.so有兩種方式,第一種通過手動執(zhí)行命令編譯出.so文件扎运,具體可以看另一篇文章ndk-build生成.so
第二種是通過添加相應配置瑟曲,讓AndroidStudio來編譯源碼
#######2.2.1 創(chuàng)建放源碼的jni文件夾
源碼存放的默認位置為app/src/main/jni中
如果工程中沒有這個文件夾,可以通過菜單創(chuàng)建豪治,當然也可以直接在這個路徑下創(chuàng)建一個叫jni的文件夾
還可以自定義目錄洞拨,然后在build.gradle中做一個資源路徑指定即可(不過這種方式我沒驗證過,后面試了一下好像是錯的):
#######2.2.2 添加編譯相關的配置
將源碼放到2.2.1中創(chuàng)建的jni目錄下鬼吵,并在該目錄下添加編譯需要的配置文件扣甲,主要就是Android.mk和Application.mk,這兩個配置文件和ndk-build生成.so中提到的是相同的齿椅,相關配置西甲誒可以看NDK官網(wǎng)build教程
也可以通過在 build.gradle中添加NDK的編譯配置琉挖,這樣就不用添加Android.mk和Application.mk了
ndk{
moduleName "jniLib" // 模塊名,編譯出來的 .so 文件
// 指定編譯平臺
// 更多平臺信息 參見https://developer.android.com/ndk/guides/abis.html#sa
abiFilters "armeabi", "armeabi-v7a", "x86"
\* Other ndk flags configurable here are
* cppFlags.add("-fno-rtti")
* cppFlags.add("-fno-exceptions")
* ldLibs.addAll(["android", "log"])
* stl = "system"
*/
}
使用gradle的好處是涣脚,自動編譯生成apk文件示辈,并且把相關的.so文件打包到apk安裝包中
3、Java代碼中調用
package com.zzl.injecthost;
public class NdkJniUtils {
static{
System.loadLibrary("jniLib");
}
public native String StringFromJNI();
}
這里System.loadLibrary("jniLib"); 這個jniLib即為在2.2.2中build.gradle內配置的moduleName
NdkJniUtils jni = new NdkJniUtils();
textView.setText(jni.StringFromJNI());
這里有個注意點
NDK下的C/C++函數(shù)和Java橋接的函數(shù)命名是有約束的遣蚀,規(guī)則如下:
Java_PackageName_ClassName_MethodName
例如下面矾麻,我有個NdkJniUtils類在com.zzl.injecthost中纱耻,在這個類中聲明一個native的jni函數(shù),則C/C++對應的函數(shù)的簽名應該為:
Java_com_zzl_injethost_NdkJniUtils_StringFromJNI(JNIEnv *env, jobject obj)
{
return (*env)->NewStringUTF(env, "Hello from JNI !");
}