##前言 上篇經過一個簡單的例子大概闡述了jni開發的基本流程,最後也編譯出了本身的so文件,本篇主要介紹怎麼引入第三方的so文件並進行調用java
零基礎帶你吃掉JNI全家桶(一)bash
經過上篇咱們知道,從Java層要調用native層的方法,要麼是靜態註冊,要麼是動態註冊,可是無論是哪種,兩個方法之間必須須要創建必定的通道關係,靜態註冊須要對應好方法名,動態註冊須要對兩個方法進行綁定,都是須要知道包名的,可是問題來了,那麼如何在個人項目中調用第三方so中的方法呢?本身的項目包名都是不同的,實際上有兩種方式:app
上面第一種方法就不說了,通常直接調用sdk便可,咱們直接看第二種,大概分爲如下幾個步驟:ide
咱們就使用上篇例子生成出來的so,咱們來調用下,從build中把so拷出來,位置以下,這裏咱們用arm架構就好了,一個是64位的,一個是32位的 post
而後放到咱們新建的一個項目中,這裏把so名字重命名下,防止混淆 gradle
而後咱們須要在build.gradle中指定so文件目錄ui
sourceSets {
main {
jni.srcDirs = []
jniLibs.srcDirs = ['src\\main\\jniLibs']
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
複製代碼
而後,由於自己本身是不須要生成so庫的,因此CMakeLists.txt中的native-lib能夠刪掉,咱們加入要引入的so庫,並與之關聯this
#定義cmake支持的最小版本號
cmake_minimum_required(VERSION 3.4.1)
#加入lib2庫 ,定義爲導入形式
add_library(lib2 SHARED IMPORTED)
#關聯lib2庫爲咱們要導入進來的libdata.so文件,ANDROID_ABI會根據自身cpu架構選擇so文件
set_target_properties( lib2
PROPERTIES IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libdata.so)
# 從系統裏查找依賴庫,可添加多個
find_library( # 例如查找系統中的log庫liblog.so
log-lib
# liblog.so庫指定的名稱即爲log,如同上面指定生成的libnative-lib.so庫名稱爲native-lib同樣
log )
複製代碼
這樣CMakeLists文件在執行的時候就會把libdata.so文件加載進來。spa
最後一步,編寫本地方法,新建一個類
package com.example.taolin.jni_project;
public class NativeHelper {
static {
System.loadLibrary("data");
}
public static native String stringFromJNI();
public static native int add(int a,int b);
}
複製代碼
主要包名,要和so中的一直的,也是上篇文章中的動態註冊代碼,這裏粘貼部分
//動態註冊
jint registerMethod(JNIEnv *env) {
jclass clz = env->FindClass("com/example/taolin/jni_project/NativeHelper");
if (clz == NULL) {
LOGD("con't find class: com/example/taolin/jni_project/NativeHelper");
}
JNINativeMethod jniNativeMethod[] = {{"stringFromJNI", "()Ljava/lang/String;", (void *) backStringToJava},
{"add", "(II)I", (void *) addNum},};
return env->RegisterNatives(clz, jniNativeMethod,
sizeof(jniNativeMethod) / sizeof(jniNativeMethod[0]));
}
複製代碼
這樣的話,就在調用的時候,就能夠找到對應的類,將Java層方法和Native層方法進行關聯起來,進行通訊
public class MainActivity extends AppCompatActivity {
// Used to load the 'native-lib' library on application startup.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(NativeHelper.stringFromJNI());
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
}
複製代碼
具體圖我就不截了,也是能成功顯示出字符串的,這樣就調用了外部so的方法,大功告成!
這裏只是最簡單的,從native層返回一個字符串,比較淺顯侷限,下篇將接着介紹下,Jni的語法,以及java層和native間更爲複雜的交互過程,對象怎麼傳輸?,native層怎麼操做java層的類?等等。
有新的想法和疑問的老哥能夠留言一塊兒討論哦,溜了溜了~