获取有效的 JNIEnv 指针

我有一个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,而不是相反。


答案 1

我想你没有办法做到这一点(可能在那里,但还没有看到它),因为这种类型的必需Java包装,所以我想使用另一个解决方案,使用Java作为你的C#调用,然后你可以这个调用从。NDK callsintermediateredirectNDK codejava

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()); 
  }
}

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

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


答案 2

我认为你可以创建另一个原生插件,它将为您提供JNIEnv。

安卓插件

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

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();

推荐