返回

C++ 无 JNIEnv 调用 Java 终极指南

java

从 C++ 调用 Java 代码:摆脱 JNIEnv 预定义

引言

在 Android 开发中,C++ 和 Java 代码通过 Java 本地接口 (JNI) 协同工作。传统上,JNIEnv 用于在两种语言之间建立桥梁。然而,为了提升 .so 文件的通用性,按需获取 JNIEnv 势在必行。本文将逐步指导您如何实现这一目标。

获取 JNIEnv

步骤 1:获取 Java 虚拟机 (JVM)

从 API 级别 31 开始,JNI_GetCreatedJavaVMs 函数可用来检索 JVM 数组。确保 NDK 升级至 r21 或更高版本。

步骤 2:加载库

JNI_GetCreatedJavaVMs 函数位于 libjvm 库中。在 CMakeLists.txt 文件中添加以下行:

target_link_libraries(your_library jvm)

步骤 3:调用 JNI_GetCreatedJavaVMs

通过 JNI_GetCreatedJavaVMs 函数获取 JVM 数组:

JavaVM* vm;
jsize vm_count;
jint result = JNI_GetCreatedJavaVMs(&vm, 1, &vm_count);

步骤 4:获取 JNIEnv

有了 JVM,使用 AttachCurrentThread 函数获取 JNIEnv:

JNIEnv* env;
result = vm->AttachCurrentThread(&env, NULL);

使用 JNIEnv

获取 JNIEnv 后,即可调用 Java 代码。完成后,使用 DetachCurrentThread 函数释放它:

vm->DetachCurrentThread();

示例代码

以下代码展示了按需获取 JNIEnv 的过程:

#include <jni.h>
#include <jvmti.h>

JNIEnv* GetJNIEnv() {
    JavaVM* vm;
    jsize vm_count;
    jint result = JNI_GetCreatedJavaVMs(&vm, 1, &vm_count);
    if (result != JNI_OK || vm_count == 0) {
        return nullptr;
    }
    JNIEnv* env;
    result = vm->AttachCurrentThread(&env, NULL);
    if (result != JNI_OK) {
        return nullptr;
    }
    return env;
}

void ReleaseJNIEnv(JNIEnv* env) {
    JavaVM* vm;
    env->GetJavaVM(&vm);
    vm->DetachCurrentThread();
}

局限性

此方法仅适用于 API 级别 31 及以上版本。对于较低版本,需要使用其他获取 JNIEnv 的方法。

常见问题解答

  • 为什么需要按需获取 JNIEnv?

    • 为了提升 .so 文件的通用性。
  • 此方法有哪些限制?

    • 仅适用于 API 级别 31 及以上版本。
  • 我可以使用这种方法调用 Java 静态方法吗?

    • 是的,可以。
  • 如何释放 JNIEnv?

    • 使用 DetachCurrentThread 函数。
  • 我可以在其他编程语言中使用此方法吗?

    • 此方法特定于 C++,但其他语言可能有类似的机制。