Android 開發(fā)過程中必然會涉及 JNI 與 NDK 開發(fā),簡單梳理下 JNI 流程
開發(fā)環(huán)境:Android Studio 3.3 、CMake :3.10 、NDK:19 ,LLDB:3.1

image.png
Android Studio 新建工程:
New Project → Native C++ → C++ Standard
默認(rèn)已經(jīng)搭建好 JNI 模板 Hello from C++
CMakeList.txt
# 有關(guān)使用CMake在Android Studio的更多信息,請閱讀文檔:https://d.android.com/studio/projects/add-native-code.html
# 設(shè)置CMake的最低版本構(gòu)建本機(jī)所需庫
cmake_minimum_required(VERSION 3.4.1)
# 創(chuàng)建并命名庫,將其設(shè)置為靜態(tài)的
# 或共享,并提供其源代碼的相對路徑。
# 你可以定義多個library庫,并使用CMake來構(gòu)建。
# Gradle會自動將包共享庫關(guān)聯(lián)到你的apk程序。
add_library( # 設(shè)置庫的名稱
native-lib
# 將庫設(shè)置為共享庫。
SHARED
# 為源文件提供一個相對路徑。
src/main/cpp/native-lib.cpp )
# 搜索指定預(yù)先構(gòu)建的庫和存儲路徑變量。因?yàn)镃Make包括系統(tǒng)庫搜索路徑中默認(rèn)情況下,只需要指定想添加公共NDK庫的名稱,在CMake驗(yàn)證庫之前存在完成構(gòu)建
find_library( # 設(shè)置path變量的名稱
log-lib
# 在CMake定位前指定的NDK庫名稱
log )
# 指定庫CMake應(yīng)該鏈接到目標(biāo)庫中,可以鏈接多個庫,比如定義庫,構(gòu)建腳本,預(yù)先構(gòu)建的第三方庫或者系統(tǒng)庫
target_link_libraries( # 指定目標(biāo)庫
native-lib
# 目標(biāo)庫到日志庫的鏈接 包含在NDK
${log-lib} )
native-lib.cpp
extern "C" JNIEXPORT jstring JNICALL
Java_com_apple_jnisample03_NativeUtils_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
MainActivity 中使用 JNI 接口
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Example of a call to a native method
TextView tv = findViewById(R.id.sample_text);
tv.setText(stringFromJNI());
}
/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
編譯 C++ 代碼到 APP 的流程
- Gradle 調(diào)用外部構(gòu)建腳本,CMakeLists.txt;
- CMake 根據(jù)構(gòu)建腳本指令去編譯一個 C++源文件,
native-lib.cpp,編譯后的產(chǎn)物扔進(jìn)共享對象庫中,并將其命名為libnative-lib.so,然后 Gradle 將其打包到 APK 中;- 運(yùn)行期間,app 的 MainActivity 會調(diào)用
System.loadLibrary()方法,加載 native library,而這個庫的原生函數(shù) stringFromJNI()
原項(xiàng)目基礎(chǔ)上添加自己的代碼
添加 getHelloJni() 接口
public class NativeUtils {
// Used to load the 'native-lib' library on application startup.
static {
System.loadLibrary("native-lib");
}
public native String stringFromJNI();
public native String getHelloJni();
}
extern "C" JNIEXPORT jstring JNICALL
Java_com_apple_jnisample03_NativeUtils_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_apple_jnisample03_NativeUtils_getHelloJni(
JNIEnv *env,
jobject instance
){
return env->NewStringUTF("Hello Jni,歡迎使用 JniSample Hello World");
}
編譯打包的 libnative-lib.so 路徑
build → intermediates → cmake → debug(release) → obj→ *libnative-lib.so
使用已經(jīng)編譯好的 *.so 文件,JNI 調(diào)用 so 文件。
main 目錄下新建文件夾jniLibs「注意」:文件夾名字大小寫不能變。
so 文件中 Java_com_apple_jnisample_NativeUtils_getHelloJni()方法,則需建立對應(yīng)包名com.apple.jnisample.NativeUtils.java 中 System.loadLibrary("native-lib");「去掉庫文件的前綴 lib 以及后綴.so」
聲明需要使用的方法即可;