android jni 使用別人編譯好的c/c++動態so庫

原文鏈接:https://blog.csdn.net/itlavn/article/details/80164456

版權聲明:本文爲博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接:https://blog.csdn.net/itlavn/article/details/80164456
別人寫好的動態庫,需要自己寫jni包一層,這樣就可以在java中調用這個庫了。其實還有第二種方法,就是使用jna來調用,這樣不用寫jni,但是今天我們不討論jna的用法。這裏介紹如何在Android Studio中,編寫jni調用他人的.so動態庫。

複製動態庫到項目
他人提供的庫,需要包含頭文件,和.so文件。

先看一下我的項目主要目錄: 


把他人提供的so庫放在libs目錄下,如圖所示,我這裏他人提供的 libtts.so 包含 armeabi 和 armeabi-v7a這兩種,我全部放在了libs目錄下。

在libs裏面新建一個header目錄,如圖所示,把so庫的頭文件放在裏面。

修改CmakeList.txt文件
在app目錄下新建CmakeLists.txt文件,其實要是在Android Studio新建項目時勾選了使用c++,那麼這個文件和一些其他配置已經有了,稍微修改就行。

先看一下我的CmakeList.txt文件:

# Sets the minimum version of CMake required to build the native
# library. You should either keep the default value or only pass a
# value of 3.4.0 or lower.

cmake_minimum_required(VERSION 3.4.1)

#引用已經有的庫
find_library( # Sets the name of the path variable.
              log-lib

               # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )

#資源文件夾的位置libs
set(distribution_DIR ${CMAKE_SOURCE_DIR}/../../../../libs)

#導入類庫,只是作爲引用,不編譯
add_library( tts
             SHARED
             IMPORTED )

#引用目標類庫是本地類庫位置在libs/armeabi/xxx.so
set_target_properties( tts
                       PROPERTIES IMPORTED_LOCATION
                       ../../../../libs/${ANDROID_ABI}/libtts.so )

#添加類庫位置在src/main/cpp/xxx.cpp需要編譯
add_library(native-lib
             SHARED
             src/main/cpp/native-lib.cpp )

#引入頭文件目錄位置
include_directories(libs/header)

#將預構建庫與你本地庫相關聯
target_link_libraries( # Specifies the target library.
                       native-lib tts

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

在你的CmakeLists.txt中參照我這個寫就行,也可以直接複製然後再根據你的項目來修改。

修改app目錄下的 build.gradle 配置文件
先看下我的build.gradle 相關部分的配置:

...
android {
    compileSdkVersion 26
    defaultConfig {
        applicationId "com.smart.astts"
        minSdkVersion 16
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        externalNativeBuild {
            cmake {
                cppFlags "-frtti -fexceptions"
            }
        }

        ndk {
            abiFilters "armeabi", "armeabi-v7a"
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    // 設置so文件路徑
    sourceSets {
        main {
            // let gradle pack the shared library into apk
            jniLibs.srcDirs = ['libs']
        }
    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
}
...

參照這個修改即可。

編寫jni代碼
在目錄app/src/main/ 下新建目錄cpp,在cpp目錄下添加native-lib.cpp文件,其實用Android Studio新建項目時勾選使用c++,這個文件已經自動新建好了。

在native-lib.cpp 裏面就有編寫我們自己的代碼,主要功能是調用so庫頭文件裏面的函數。jni裏面的方法名不用自己手寫,下面簡單示例一下。

我在MainActivity.java中新建一個native方法,這個方法返回native提供的字符串。

 public native String stringFromJNI();
1
2
這時候這個方法是紅色的,因爲jni裏面還沒有與之對應的方法。

鼠標指針點到方法名上,鍵盤按 “Alt”+“Enter”鍵,出來快捷菜單,選中 “Create function ….” 按“Enter”鍵確認。現在 在native-lib.cpp文件裏就有這個方法了。我們這個方法是要返回一個字符串,所以在native-lib.cpp稍微修改一下這個方法:

extern "C"
JNIEXPORT jstring JNICALL
Java_com_smart_astts_MainActivity_stringFromJNI(JNIEnv *env, jobject instance) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

加載jni庫和so動態庫
然後在MainActivity中靜態加載我們編寫的jni庫,同時也並加載第三方的so庫:

   static {
        System.loadLibrary("tts");
        System.loadLibrary("native-lib");
    }

運行,測試jni是否編譯成功
運行一下,如果app成功調用了我們的native方法 stringFromJNI(),我們之前的配置就算寫對了。

調用第三方so庫的方法
接下來就可以根據第三方庫的頭文件,在java代碼裏寫對應的native方法,然後在jni裏面調用頭文件裏面對應的方法。
————————————————
版權聲明:本文爲CSDN博主「itlavn」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/itlavn/article/details/80164456

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章