Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting Valid JNIEnv pointer

I have a C++ dll that I want to use in Unity by exporting the functions to C#. The Unity project runs on Android devices and the C++ code makes use of java. To initialize the C++ I need to call the following function first:

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

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

    //Do other proprietary things
}

In Unity I have the following exported Dll function

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

My question is How do I get a JNIEnv pointer in my C# class to then pass as a parameter into this function?

I am not the creator of this API and don't have the access to modify it, so I need to get the JavaVM from the JNIEnv, not the other way around.

like image 438
user1782677 Avatar asked Aug 09 '16 23:08

user1782677


People also ask

What is JNIEnv * env?

jobject NewGlobalRef(JNIEnv *env, jobject obj); Creates a new global reference to the object referred to by the obj argument. The obj argument may be a global or local reference.

How android JNI works?

It defines a way for the bytecode that Android compiles from managed code (written in the Java or Kotlin programming languages) to interact with native code (written in C/C++). JNI is vendor-neutral, has support for loading code from dynamic shared libraries, and while cumbersome at times is reasonably efficient.

What is a JNI Bridge?

Introduction to Java Native Interface: Establishing a bridge between Java and C/C++ JNI (Java Native Interface) is a foreign function interface that allows code running on JVM to call (or be called by) native applications. Using JNI, one can call methods written in C/C++ or even access assembly language.


1 Answers

I guess there is no way you can do this (might be there but haven't seen it yet) because this type of NDK calls required java wrapping around so i would like to purpose an another solution that use Java as an intermediate for your C# calls and then you can redirect this call to NDK code from 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

And in your java file do this

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

When you declare native method the javah automatically generate a ndk call definition with javaEnv and jobject as parameter so i guess you only need to pass class loader here .You can try this link and this links in case for more clarification.

Good Luck.Hope This will help.

like image 122
Pavneet_Singh Avatar answered Oct 16 '22 15:10

Pavneet_Singh