我有一个Android应用程序,其中包含Java和C++代码.我的C++代码被Bundle 到不同的.so文件中,并且可以从Java或其他.so文件中调用.从一些.so文件中,我需要调用一些Java代码.

要调用Java代码,我认为我们需要JNIEnv.这可以在加载库时调用JNI_onLoad方法时接收,也可以在Java调用C++代码时在方法参数中传递JNIEnv时接收.要调用Java代码,推荐的方法似乎是保存JNIEnv,并在以后调用Java代码时使用它.

但在我的例子中,我想让我的.so文件保持通用,这样它们就可以在不同的操作系统上使用.因此,我不希望跨多个依赖项传递JNIEnv.What I am looking for is to get JNIEnv on demand.

我看到我可以通过使用JNI_GetCreatedJavaVms方法获取JVM,然后使用JVM实例获取JNIEnv来实现这一点.问题是这个方法似乎没有在jni.h中定义,但只提供了类似以下内容的声明:

    /*
     * VM initialization functions.
     *
     * Note these are the only symbols exported for JNI by the VM.
     */
    jint JNI_GetDefaultJavaVMInitArgs(void*);
    jint JNI_CreateJavaVM(JavaVM**, JNIEnv**, void*);
    jint JNI_GetCreatedJavaVMs(JavaVM**, jsize, jsize*);

我知道这些文件应该从其他库中加载,但找不到任何有关我需要导入哪些库、需要在C++文件中导入哪些头文件/源文件以及如何使用该方法的文档.有人能帮上忙吗?

我发现了这个GitHub issue,它表明这些方法没有在更早的时候导出,现在只从API级别31导出.但我不清楚应该如何访问这些导出的方法.

我正在使用NDK的r18b来构建我的代码,当我try 使用JNI_GetCreatedJavaVM时,它抛出以下错误:

  [x86_64] SharedLibrary  : libJniPoc.so
  /workplace/alias/workspace/src/JniPoc/src/main/cpp/core/InfoProvider.cpp:16: error: undefined reference to 'JNI_GetCreatedJavaVMs'
  clang++: error: linker command failed with exit code 1 (use -v to see invocation)
  make: *** [/workplace/alias/workspace/build/JniPoc/JniPoc-1.0/AL2_x86_64/DEV.STD.PTHREAD/build/intermediates/ndkBuild/debug/obj/local/x86_64/libJniPoc.so] Error 1

那么,我需要做些什么才能完成编译工作,又需要做些什么才能让它在运行时工作呢?

推荐答案

如果您的目标API级别为31或更高,则该函数已存在,因此您不需要执行任何操作.根据apilevels.com,如果你想在应用store 上发布你的应用程序,你需要瞄准31anyway版本. 你唯一需要做的就是链接libnativehelper,你可以通过:

target_link_libraries(JniPoc PUBLIC -lnativehelper)

无论出于何种原因,如果这不是一个选项,您可以创建自己的定义.正如您所提到的,JNI_Onload函数接收一个JavaVM参数,因此您可以将其保存在安全的地方:

static JavaVM *g_vm = nullptr;
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
  g_vm = vm;
  // other code
}

JNIEXPORT jint JNICALL
JNI_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs) {
  if (bufLen < 1) {
    return JNI_ERR;
  }

  if (!g_vm) {
    *nVMs = 0;
  } else {
    *nVMs = 1;
    vmBuf[0] = g_vm;
  }
  return JNI_OK;
}

请注意,这只是一个部分解决方案,我不确定它将在are,31和更高版本的设备上做什么.你可以试着在定义上加__attribute__((weak)),但这只是个猜测.

Android相关问答推荐

Kotlin多平台向导,不兼容版本(ANP 8.2.0)ANP 8.1.2

如何解决Android Studio中的in fragment问题

原因平滑滚动的滞后懒惰列在android jetpack compose

如何在停止和销毁时更改函数中Firebase实时数据库的子项的值我试过了,但这不起作用.请使用Kotlin

在一列中垂直对齐两个框

如何在Android中打印到命令行

FireBase Android ChildEventListener在被规则拒绝时触发(RTDB)

Kotlin为多个控件设置一个侦听器

Dispatchers中的Kotlin协同程序.Main没有';t块主螺纹

是否可以在 Android 应用程序的 Wifi 设置中为 DNS 服务器设置自定义 IP?

Android 应用程序从 Android Studio 安装,但不是作为 .apk 在外部安装.抛出java.lang.UnsatisfiedLinkError

在 Material 3 TopAppBar 代码的哪个位置定义了填充?

如何在 Delphi 和 Android 上避免 Indy Socket Error #13 Access denied 异常?

如何在 Jetpack Compose 中的特定位置绘制图像

设置背景图片组成Column

如何对齐文本和图标可组合,以便即使在文本溢出后它们也能保持在一起?

是什么让 Android Studio 中的按钮变成紫色?加上新手的其他奇怪行为

未使用的内容填充参数

在使用 Retrofit 和 Room 时,我是否需要提及协程调度程序?

等到上一个事件完成 Rx