unityplayeractivity unity plugin activity java android unity3d dll jni

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.

Complementos para Android

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á.