1. 程式人生 > >NDK學習( 二),在NDK開發中引入第三方庫(AndroidStudio Cmake)

NDK學習( 二),在NDK開發中引入第三方庫(AndroidStudio Cmake)

在NDK中可能需要複用之前已經編譯好的so檔案,所以本章的目標是給一個之前編譯好的so檔案外加一個需要呼叫介面的標頭檔案,在現在專案中複用。 在本次實踐過程中,已經有編譯完成的各種cpu架構的libstringutil-lib.so以及標頭檔案,Stringutil.h 標頭檔案中簡單定義了兩個介面: class StringUtil { public: static char* toLower(char* chars); static char* toUpper(char* chars); }; 顧名思義上述介面已在libstringutil-lib.so中實現 現有工程需要呼叫這些介面,步驟如下: 1、在java層建立native介面
package dev.mars.jnidemo;
public class StringUtils {
    static {
        System.loadLibrary("native-lib");
}
    public static native String toLower(String str);
    public static native String toUpper(String str);
}

2、由Android Studio自動生成native層介面定義,native-lib是實現介面的cpp檔案:
extern "C" {
JNIEXPORT 
jstring JNICALL Java_dev_mars_jnidemo_StringUtils_toLower(JNIEnv *env, jclass type, jstring str_) { const char *str = env->GetStringUTFChars(str_, 0); char* str2 =new char[strlen(str)]; strcpy(str2,str); StringUtil::toLower(str2); return env->NewStringUTF(str2); } JNIEXPORT jstring JNICALL
Java_dev_mars_jnidemo_StringUtils_toUpper(JNIEnv *env, jclass type, jstring str_) { const char *str = env->GetStringUTFChars(str_, 0); char* str2 =new char[strlen(str)]; strcpy(str2,str); StringUtil::toUpper(str2); return env->NewStringUTF(str2); }
}

此時編譯器應該找不到StringUtil的定義,因此需要將Stringutil.h拷貝到cpp檔案所在的資料夾下,本工程中如圖所示,新建一個include資料夾,將標頭檔案拷貝過去: 然後在native-lib.cpp中加入標頭檔案的引用:

#include <string>
#include <android/log.h>
#include "include/StringUtil.h"

3、將所有so檔案拷貝到工程的libs/jni目錄下
4、修改app下的gradle檔案,在android{}中加入如下程式碼,將so檔案作為引用
sourceSets {
    main {
        jniLibs.srcDirs = ['./libs/jni']
    }
}

5、下面是最為關鍵的CmakeLists.txt的配置
cmake_minimum_required(VERSION 3.4.1)

#定義變數ProjectRoot為工程根目錄,用相對路徑沒通過編譯,可能是路徑寫錯,以後再試
#本次使用絕對路徑作為引數
set(ProjectRoot G:/AndroidStudioProjects/JNIDemo)

#將native-lib加入到編譯源中
add_library( native-lib SHARED src/main/jni/native-lib.cpp )

#動態方式載入 stringutil-lib是libxxxx.so的xxxx部分
add_library(stringutil-lib SHARED IMPORTED)

#設定要連線的so的相對路徑,${ANDROID_ABI}表示so檔案的ABI型別的路徑,這一步引入了動態加入編譯的so
set_target_properties(stringutil-lib  PROPERTIES IMPORTED_LOCATION ${ProjectRoot}/app/libs/jni/${ANDROID_ABI}/libstringutil-lib.so)

find_library( log-lib log )

#配置載入native依賴
#include_directories( ${ProjectRoot}/app/src/main/jni/include )

#這裡多出了引用的stringutil-lib
target_link_libraries(
                       native-lib
                       stringutil-lib
                       ${log-lib} )

6、測試程式碼 總結 最為關鍵的兩個步驟 1、在gradlle中指定本地的jni相對路徑 2、在CmakeLists.txt中指定加入編譯的so及其絕對路徑 #動態方式載入 stringutil-lib是libxxxx.so的xxxx部分 add_library(stringutil-lib SHARED IMPORTED) #設定要連線的so的相對路徑,${ANDROID_ABI}表示so檔案的ABI型別的路徑,這一步引入了動態加入編譯的so set_target_properties(stringutil-lib PROPERTIES IMPORTED_LOCATION ${ProjectRoot}/app/libs/jni/${ANDROID_ABI}/libstringutil-lib.so) #這裡多出了引用的stringutil-lib target_link_libraries( native-lib stringutil-lib ${log-lib} ) 由於時間不多,未調試出在CmakeLists.txt 中使用相對路徑的辦法,我在編譯中總是報找不到so的錯誤。有任何問題歡迎交流。 參考: