返回
C++ 无 JNIEnv 调用 Java 终极指南
java
2024-03-16 10:11:58
从 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++,但其他语言可能有类似的机制。