2016-08-09 20 views
16

Tôi có một dll C++ mà tôi muốn sử dụng trong Unity bằng cách xuất các hàm sang C#. Dự án Unity chạy trên các thiết bị Android và mã C++ sử dụng java. Để khởi tạo C++ tôi cần phải gọi hàm sau đây đầu tiên:Nhận con trỏ JNIEnv hợp lệ

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

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

    //Do other proprietary things 
} 

Trong Unity Tôi có sau chức năng DLL xuất khẩu

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

Câu hỏi của tôi là Làm thế nào để có được một con trỏ JNIEnv trong C# lớp để sau đó vượt qua như một tham số vào chức năng này?

Tôi không phải là người tạo ra API này và không có quyền truy cập để sửa đổi nó, vì vậy tôi cần lấy JavaVM từ JNIEnv, không phải theo cách khác.

+0

Tôi tin rằng bạn có thể tìm thấy một câu trả lời tại đây-> http://stackoverflow.com/questions/21951711/how-to-pass-a-jni-c-sharp-class-into-java-or-handle-this- hoặc tạo tùy chỉnh của bạn cuộc gọi java bằng tài liệu Oracle -> situationhttp: //docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/design.html#wp715 Dù sao thì cũng là một câu hỏi hay. – Cabrra

Trả lời

3

Tôi đoán không có cách nào bạn có thể làm điều này (có thể có nhưng chưa thấy nó) vì loại NDK calls yêu cầu java gói xung quanh vì vậy tôi muốn mục đích một giải pháp khác sử dụng Java như là intermediate cho các cuộc gọi C# của bạn và sau đó bạn có thể redirect cuộc gọi này tới NDK code từ 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 

Và trong file java của bạn làm điều này

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

Khi bạn khai báo phương pháp mẹ đẻ javah tự động tạo ra một định nghĩa cuộc gọi ndk với javaEnv và jobject như tham số vì vậy tôi đoán bạn chỉ cần phải vượt qua lớp loader tại đây. Bạn có thể thử các liên kết linkthis này trong trường hợp cần làm rõ thêm.

Good Luck.Hope Điều này sẽ hữu ích.

+1

Điều này đã giúp, và điều này hoạt động! Tôi xác nhận với việc thực hiện. – Maestro

2

Tôi nghĩ bạn có thể tạo một plugin gốc khác sẽ cung cấp cho bạn JNIEnv.

Plugins for Android

Tổng kết bài viết này, bạn nên thử một cái gì đó giống như (mã giả chưa được kiểm tra) này:

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

Sau đó, trong C#

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

Tôi nghĩ rằng JNI_OnLoad chỉ được gọi nếu một mô-đun Java yêu cầu một cách rõ ràng khi tải thư viện (System.loadLibrary). – Maestro

Các vấn đề liên quan