Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

在 Android 应用中调用 C++ 代码并在新线程中执行 Java 静态方法 #1

Open
cnwutianhao opened this issue Jan 5, 2024 · 0 comments

Comments

@cnwutianhao
Copy link
Owner

本文将通过一个使用 Kotlin 和 C++ 编写的 Android 应用案例,展示如何利用 JNI 实现 Java 层与本地 C++ 代码的交互。

Kotlin 代码:

package com.tyhoo.jni

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.tyhoo.jni.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        binding.sampleText.setOnClickListener {
            Log.d(TAG, "nativeMethod")
            nativeMethod()
        }
    }

    private external fun nativeMethod()

    companion object {
        private const val TAG = "Tyhoo"

        // Used to load the 'jni' library on application startup.
        init {
            System.loadLibrary("jni")
        }

        @JvmStatic
        fun staticMethod() {
            Log.d(TAG, "staticMethod")
        }
    }
}

这是 Kotlin 语言编写的 Android 应用程序中的 MainActivity 类,其中声明了一个名为 nativeMethod 的本地方法。该方法会在点击 sampleText 视图时被调用,从而触发 native 方法的执行。在 companion object 中还定义了一个名为 staticMethod 的静态方法,它会在应用程序启动时被加载,用于在 Java 层调用本地方法。这个静态方法可以从 Java 代码中直接调用,而不需要使用 JNI 接口函数。

C++ 代码:

#include <jni.h>
#include <string>
#include <android/log.h>

#define LOG_TAG "Tyhoo"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

#define CLASSNAME "com/tyhoo/jni/MainActivity"

typedef struct {
    JavaVM *vm;
    jclass clazz;
} tyhoo_vm;

static tyhoo_vm javaVM;

JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *unused) {
    JNIEnv *env = nullptr;
    if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        LOGD("JNI_OnLoad GetEnv failed\n");
        return -1;
    }

    jclass clazz = env->FindClass(CLASSNAME);
    if (!clazz) {
        LOGD("FindClass %s failed\n", CLASSNAME);
        return -1;
    }

    javaVM.vm = vm;
    javaVM.clazz = (jclass) env->NewGlobalRef(clazz);

    LOGD("JNI_OnLoad, vm: %p, clazz: %p \n", javaVM.vm, javaVM.clazz);
    return JNI_VERSION_1_6;
}

void JNI_OnUnload(JavaVM *vm, void *unused) {
    JNIEnv *env = nullptr;
    if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
        LOGD("JNI_OnLoad GetEnv failed\n");
        return;
    }
    env->DeleteGlobalRef(javaVM.clazz);
}

void callJavaStaticMethod() {
    JNIEnv *env = nullptr;
    jint res = javaVM.vm->AttachCurrentThread(&env, nullptr);
    if (res != JNI_OK) {
        return;
    }

    jclass clazz = javaVM.clazz;
    if (clazz == nullptr) {
        return;
    }

    jmethodID method = env->GetStaticMethodID(clazz, "staticMethod", "()V");
    env->CallStaticVoidMethod(clazz, method);
}

void *thread_func(void *arg) {
    callJavaStaticMethod();
    return nullptr;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_tyhoo_jni_MainActivity_nativeMethod(JNIEnv *env, jobject thiz) {
    pthread_t thread;
    pthread_create(&thread, nullptr, thread_func, nullptr);
}

这是 C++ 语言编写的 JNI 接口函数,用于在 Java 层调用本地方法。这个接口函数的作用是创建新线程,并在新线程中调用 callJavaStaticMethod 方法,这个方法会获取当前线程的 JNIEnv 对象和 Java 类对象,并通过这些对象调用 Java 层的静态方法 staticMethod。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant