Android JNI NDK 開發(fā)

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 的流程

  1. Gradle 調(diào)用外部構(gòu)建腳本,CMakeLists.txt;
  2. CMake 根據(jù)構(gòu)建腳本指令去編譯一個 C++源文件,native-lib.cpp,編譯后的產(chǎn)物扔進(jìn)共享對象庫中,并將其命名為libnative-lib.so,然后 Gradle 將其打包到 APK 中;
  3. 運(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 路徑

buildintermediatescmakedebug(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」
聲明需要使用的方法即可;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容