NDK<第四篇>:c++調(diào)用so庫

【第一步】 編寫C++代碼

Test.cpp

int test() {
    return 10086;
}

【第二步】 生成so庫

在AS中配置好cmake環(huán)境,將 Test.cpp 放入工程,編譯出 so 庫。(第一章節(jié)有詳細(xì)介紹)

【第三步】 聲明 extern int test(),并調(diào)用test函數(shù)

#include <jni.h>
#include <string>
#include <pthread.h>
#include <android/log.h>
#define LOG_TAG "native-lib"
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

using namespace std;

// 如果是C,需要添加 extern "C"{}
extern int test();

// 全局變量
JavaVM* javaVm;
struct Context {
    jobject obj;
};

/**
 * 子線程
 * @param args
 * @return
 */
void* threadTask(void* args) {
    LOGI("start thread task");
    LOGE("執(zhí)行test函數(shù):%d", test());
    if (javaVm == NULL) {
        LOGE("javaVm is null");
        return JNI_FALSE;
    }
    JNIEnv* env;
    // 將native線程添加到JVM中
    jint isAttach = javaVm->AttachCurrentThread(&env, 0);
    if (isAttach != JNI_OK) {
        LOGE("attact thread error");
        return JNI_FALSE;
    }
    Context* context = static_cast<Context *>(args);
    // 得到字節(jié)碼
    jclass clazz = env->GetObjectClass(context->obj);
    // 得到methodId
    jmethodID methodId = env->GetMethodID(clazz, "updateUI", "()V");
    // 執(zhí)行方法
    env->CallVoidMethod(context->obj, methodId);
    // 分離
    javaVm->DetachCurrentThread();
    delete context;
    context = NULL;
    return JNI_FALSE;
}

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm,void*) {
    LOGI("in JNI_Onload");
    javaVm = vm;
    return JNI_VERSION_1_6;
}

extern "C" JNIEXPORT void JNICALL
Java_com_nobug_jniproject_MainActivity_testThread(JNIEnv *env, jobject obj) {
    LOGI("testThread from C");
    Context* context = new Context;
    context->obj = env->NewGlobalRef(obj);
    pthread_t pid;
    // 啟動一個線程
    pthread_create(&pid, 0,threadTask, context);
}

【第四步】 Java 調(diào)用 testThread

public class MainActivity extends AppCompatActivity {

    private ActivityMainBinding binding;
    private JNI jni = new JNI();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        binding.sampleText.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                testThread();
            }
        });
    }

    public native void testThread();

    public void updateUI() {
        if (Looper.getMainLooper() == Looper.myLooper()) {
            Toast.makeText(MainActivity.this, "updateUI", Toast.LENGTH_SHORT).show();
        } else {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(MainActivity.this, "updateUI", Toast.LENGTH_SHORT).show();
                }
            });
        }
    }
}

【第五步】 注意Gradle配置

plugins {
    id 'com.android.application'
}

android {
    compileSdk 32

    defaultConfig {
        applicationId "com.nobug.jniproject"
        minSdk 21
        targetSdk 32
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                abiFilters 'armeabi-v7a'
                cppFlags "-std=c++11 -frtti -fexceptions -Os -Wall"
            }
        }
        ndk { // "armeabi-v7a", "arm64-v8a"
            abiFilters 'armeabi-v7a'
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    externalNativeBuild {
        cmake {
            path file('CMakeLists.txt')
            version '3.18.1'
        }
    }
    buildFeatures {
        viewBinding true
    }
}

dependencies {

    implementation 'androidx.appcompat:appcompat:1.3.0'
    implementation 'com.google.android.material:material:1.4.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

【第六步】 cmake配置

 cmake_minimum_required(VERSION 3.18.1)

 # project("jniproject")

 # 導(dǎo)入庫目錄
 # include_directories("C:/Program Files/Java/jdk-18.0.1.1/include")

 # 生成一個動態(tài)庫(windows:dll,android:so)
 add_library(jniproject SHARED src/main/cpp/native-lib.cpp)

 # 設(shè)置一個變量
 # CMAKE_CXX_FLAGS c++參數(shù)
 # CMAKE_C_FLAGS c參數(shù)
 # CMAKE_C_FLAGS = --sysroot=XX
 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi-v7a")
 #add_library(Test SHARED IMPORTED)
 #set_target_properties(Test PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi-v7a/libTest.so)


 # 生成可執(zhí)行文件(生成exe文件, 在VS工具上可用)
 # add_executable (jniproject1 native-lib.cpp)

 # log-lib 是變量名稱  log是動態(tài)庫名稱 將liblog.so或liblog.a的路徑賦值給log-lib
 find_library(log-lib log)

 # 鏈接ndk自帶的庫
 target_link_libraries(
         jniproject        # 鏈接 libjniproject.so
         Test              # 鏈接 libTest.so
         ${log-lib})       # 鏈接 liblog.so

其中

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi-v7a")

可以改成:

 add_library(Test SHARED IMPORTED)
 set_target_properties(Test PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi-v7a/libTest.so)

【第七步】 運(yùn)行app,查看工作臺中是否有相關(guān)日志

image.png

[本章完...]

?著作權(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)容