java - unity - Obtener el puntero JNIEnv válido
unity c++ plugin (2)
Tengo un dll de C ++ que quiero usar en Unity al exportar las funciones a C #. El proyecto de Unity se ejecuta en dispositivos Android y el código de C ++ utiliza Java. Para inicializar C ++, necesito llamar primero a la siguiente función:
void api_initialize(JNIEnv* env, jobject* app_context, jobject* class_loader) {
JavaVM* vm = nullptr;
env->GetJavaVM(&vm);
if (!vm) {
return;
}
//Do other proprietary things
}
En Unity tengo la siguiente función Dll exportada
[DllImport (dllName)]
private static extern void api_initialize (IntPtr java_env, IntPtr app_context, IntPtr class_loader);
Mi pregunta es ¿Cómo obtengo un puntero JNIEnv en mi clase C # para luego pasarlo como parámetro en esta función?
No soy el creador de esta API y no tengo acceso para modificarla, así que necesito obtener JavaVM de JNIEnv, y no al revés.
Creo que puedes crear otro plugin nativo que te dará JNIEnv.
Resumiendo este artículo, debe intentar algo como esto (pseudo código no probado) :
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;
}
Luego en C #
[DllImport ("PluginName")]
private static extern IntPtr GetJniEnv();
Supongo que no hay forma de que puedas hacer esto (podría estar allí pero aún no lo he visto) porque este tipo de NDK calls
requieren envoltura de Java, por lo que me gustaría diseñar otra solución que use Java como intermediate
para tu C # llamadas y luego puede redirect
esta llamada al NDK code
desde java
.
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
Y en tu archivo java haz esto
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());
}
}
Cuando declaras el método nativo, javah
genera automáticamente una definición de llamada ndk con javaEnv y jobject como parámetro, así que supongo que solo necesitas pasar el cargador de clases aquí. Puedes probar este enlace y este enlace en caso de que haya más aclaraciones.
Buena suerte. Espero Esto ayudará.