【问题标题】:Getting Valid JNIEnv pointer获取有效的 JNIEnv 指针
【发布时间】:2016-08-09 23:52:23
【问题描述】:

我有一个 C++ dll,我想通过将函数导出到 C# 来在 Unity 中使用它。 Unity 项目在 Android 设备上运行,C++ 代码使用 java。要初始化 C++,我需要先调用以下函数:

void api_initialize(JNIEnv* env, jobject* app_context, jobject* class_loader) {

    JavaVM* vm = nullptr;
    env->GetJavaVM(&vm);
    if (!vm) {
      return;
    }

    //Do other proprietary things
}

在 Unity 中,我有以下导出的 Dll 函数

    [DllImport (dllName)]
    private static extern void api_initialize (IntPtr java_env, IntPtr app_context, IntPtr class_loader);

我的问题是如何在我的 C# 类中获取 JNIEnv 指针,然后将其作为参数传递给该函数?

我不是这个 API 的创建者,也没有修改它的权限,所以我需要从 JNIEnv 获取 JavaVM,而不是反过来。

【问题讨论】:

  • 我相信您可以在这里找到答案-> stackoverflow.com/questions/21951711/… 或使用 Oracle 文档创建自定义 java 调用 -> 情况http://docs.oracle.com/javase/6/docs/ technotes/guides/jni/spec/design.html#wp715 无论如何是一个很好的问题。
  • 您可以为此使用 JNI_GetCreatedJavaVMs 吗?

标签: java android unity3d dll java-native-interface


【解决方案1】:

我想你没有办法做到这一点(可能在那里但还没有看到)因为这种类型的 NDK calls 需要 java 环绕,所以我想使用另一个使用 Java 作为解决方案intermediate 用于您的 C# 调用,然后您可以将 redirectjava 调用到 NDK code

using UnityEngine;
using System.Collections;
using System.IO;

#if UNITY_ANDROID
public class JavaCallPlugin {

  // Avoid invalid calls
  public static void initiateNDK() {
    if (Application.platform != RuntimePlatform.Android)
          return;

    var pluginClass = 
        new AndroidJavaClass("com.package.class.UnityJavaDelegate");
    AndroidJavaObject plugin = 
        pluginClass.CallStatic<AndroidJavaObject>("obj");
    return plugin.Call("javaCallToNDK");
  } 
}
#endif

在你的 java 文件中这样做

package com.package.class;

import android.content.ContentValues;
import android.content.Intent;
import android.os.Environment;

public class UnityJavaDelegate{
  private static UnityJavaDelegate obj;

  // define function call to your NDK method with native keyword
  private native void api_initialize(); 

  static {
    System.loadLibrary("yourlibraryname"); // setup your ndk lib to use 
  }

  public static UnityJavaDelegate getObj() {
    if(m_instance == null)
       obj= new UnityJavaDelegate();
    return obj;
  }

  private UnityJavaDelegate(){
  }

  public void javaCallToNDK(){
    // this call may not work because i haven't passed class 
    // loader TO NDK before, if not then you should try links 
    // at the bottom of the post to know how to pass customize 
    // as parameter to NDK.

    // put your call to NDK function here 
    api_initialize(this.getClass().getClassLoader()); 
  }
}

当您声明本机方法时,javah 会自动生成一个以 javaEnv 和 jobject 作为参数的 ndk 调用定义,所以我想您只需要在此处传递类加载器。您可以试试这个 linkthis 链接以防万一以获得更多说明。

祝你好运。希望这会有所帮助。

【讨论】:

  • 这有帮助,而且有效!我确认了实施。
【解决方案2】:

我认为您可以创建另一个本机插件来为您提供 JNIEnv。

Plugins for Android

总结这篇文章,你应该试试这样的(未经测试的伪代码)

JavaVM* g_JVM; // JavaVM is valid for all threads, so just save it globally 

extern "C" {
    JNIEnv* GetJniEnv();
}

// The VM calls JNI_OnLoad when the native library is loaded
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
    g_JVM = vm;
    return JNI_VERSION_1_6;
}

// The JNI interface pointer (JNIEnv) is valid only in the current thread.
JNIEnv* GetJniEnv() {
    JNIEnv* jni_env = 0;
    g_JVM->AttachCurrentThread(&jni_env, 0);
    return jni_env;
}

然后在 C# 中

[DllImport ("PluginName")]
private static extern IntPtr GetJniEnv();

【讨论】:

  • 我认为 JNI_OnLoad 只有在 Java 模块明确请求加载库 (System.loadLibrary) 时才会被调用。
  • 使用GetJniEnv 作为函数名在这里会造成混淆,因为在 C++ 世界中需要指针。但是我刚刚从 Unity3d C# 脚本[DllImport("mynative")] private static extern float helloWorld(); 测试了这个解决方案,它在 Unity 2021.1.25f 中完美运行。
【解决方案3】:

扩展 Vyacheslav Gerasimov 的回答,此代码经过测试并无需任何额外工作即可投入使用:

JNIEnv* jni_env = NULL;
JavaVM* JVM;

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
    JVM = vm;
    if (vm->GetEnv((void**)&jni_env, JNI_VERSION_1_6) != JNI_OK)
        __android_log_print(ANDROID_LOG_ERROR, "Unity", "ERROR: GetEnv failed")

    return JNI_VERSION_1_6;
}

JNI_OnLoad 由 Unity/Java 自动调用

不需要 C#,因为您可以在 c++ 中传递 jni_env 或 JVM 变量。

【讨论】:

    猜你喜欢
    • 2012-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多