簡體   English   中英

如何將JNI C#類傳遞給Java或處理這種情況?

[英]How to pass a JNI C# class into Java or handle this situation?

我試圖從C#調用Java方法,它從java中調用如下:

EgamePay.pay(thisActivity, payAlias, new EgamePayListener() {
            @Override
            public void paySuccess(String alias) {
            }

            @Override
            public void payFailed(String alias, int errorInt) {
            }

            @Override
            public void payCancel(String alias) {
            }
        });

前兩個參數都可以,但是如何在C#中傳遞EgamePayListner? 簡單地創建具有相同功能的C#類將無法正常工作......

這是我目前正在做的事情:

using (AndroidJavaClass jc = new AndroidJavaClass("cn.egame.terminal.smspay.EgamePay"))
        {
            System.IntPtr cls_Activity = AndroidJNI.FindClass("com/unity3d/player/UnityPlayer");
            System.IntPtr fid_Activity = AndroidJNI.GetStaticFieldID(cls_Activity, "currentActivity", "Landroid/app/Activity;");
            object[] p = { fid_Activity, "payAlias", new EgamePayListener() };
            jc.CallStatic("pay", p);
        }

..

 class EgamePayListener
    {
        public void paySucess(string alias)
        {
        }

        public void payFailed(string alians, int errorInt)
        {
        }

        public void payCancel(string alias)
        {
        }
    }

顯然這是錯的,我怎么能處理這種情況,以便在這些函數被觸發時我可以在C#land中得到通知?

您可以通過參考在VS201X中將這些項目鏈接在一起。 從這里開始,您應該能夠填寫其他層(JNI / Java),然后開始在系統周圍傳遞指針(作為一個長整數)並調用您的函數。

C#層

Program.cs中

namespace CSharpLayer
{
class Program : CLILayer.CLIObject
{
    static void Main(string[] args)
    {
        Program p = new Program();

        p.invokeJava();
    }

    public void invokeJava()
    {
        //Call into CLI layer function to loadJVM, call Java code, etc
        loadJava();
    }

    public override void callback(string data)
    {
        //This will be called from the CLI Layer.
    }

}
}

C ++ / CLI層 - 具有CLR支持的DLL C ++項目(/ clr)

CLIObject.h

#pragma once

namespace CLILayer
{
public ref class CLIObject
{
    public:
        CLIObject();
        ~CLIObject();

        void loadJava(System::String^ jvm, System::String^ classpath);

        virtual void callback(System::String^ data) = 0;
};
}

CLIObject.cpp

#include "CLIObject.h"
#include <string>

#include <msclr/marshal_cppstd.h>
#include <msclr/marshal.h>

using namespace msclr::interop;
using namespace CLILayer;

CLIObject::CLIObject()
{   
}

CLIObject::~CLIObject()
{
}
CLIObject::loadJava(System::String^ jvmLocaion, System::String^ classpath)
{
    std::string _jvmLoc = marshal_as<std::string>(jvmLocation);
    std::string _classpath = marshal_as<std::string>(classpath);
}

這是JNI字段描述符

JavaLanguage     Type
--------------------------------
Z                 boolean
B                 byte
C                 char
S                 short
I                 int
J                 long
F                 float
D                 double
Ljava/lang/String; string
[Ljava/lang/Object; object[]

方法描述符使用字段描述符並描述Java方法的結構。 方法描述符中的字段描述符之間沒有空格。

除了由V表示的void返回類型之外,所有其他返回類型都使用字段描述符。 下表描述了Java方法聲明和相應的JNI描述符。 當通過JNI從C#調用Java方法時,使用JNI方法描述符。

 Java Method Declaration    JNI Method Descriptor
----------------------------------------------------
 String foo();          "()Ljava/lang/String;"
 Void bar(int I, bool b);   (IZ)V

首先需要做的是創建一個包含要傳遞給Java虛擬機的所有參數的字典對象。 在下面的示例中,我正在設置類路徑,它將告訴JVM在哪里查找類和包。

private Dictionary<string, string> jvmParameters = new Dictionary<string, string>();
jvmParameters.Add("-Djava.class.path", Location of the java class);

將JVM參數分配給字典對象后,即可創建JavaNativeInterface的實例。 創建后,需要使用JVM參數調用LoadJVM方法,然后加載Java虛擬機。 加載后,用戶調用該方法來實例化Java對象(請注意,InstantiateJavaObject方法的使用是可選的,因為用戶可能只想調用靜態方法,在這種情況下,不需要調用此方法;但是,它不會造成任何傷害)。

Java = new JavaNativeInterface();
Java.LoadVM(jvmParameters, false);
Java.InstantiateJavaObject(Name of the java class excluding the extension);

一旦加載了JVM並實例化了類,用戶就可以調用他們想要的任何方法。 首先創建一個對象列表,其中包含要傳遞給Java方法的所有參數。 由於它是一個對象列表,它可以保存不同類型的參數,因為所有內容都從一個對象繼承。

 List<object> olParameters = new List<object>();
 olParameters.Add(Value of the parameter to be passed to the java method);

接下來,只需調用泛型方法CallMethod,將Java方法的返回類型作為模板類型傳遞。 在下面的示例中,我調用了CallMethod,這意味着我想要調用的Java方法的返回類型是一個字符串。

接下來,傳入要調用的Java方法的名稱和方法描述符(見上文); 最后,傳遞所有參數的列表。 (注意:如果不需要參數,則傳入一個空列表。)

Java.CallMethod<string>("AddTwoNumbers", "(IILjava/lang/String;)I", olParameters);

好吧,我想這包裝了一切,但請記住,你可以用JNI做更多的事情。 測試應用程序只是一種快速而骯臟的方式來演示JNI組件的基礎知識。 全面了解JNI。

您可以通過此鏈接獲得更多信息

如果你在Unity3D的上下文中,從Java本機代碼到Unity3D C#腳本交互的更好方法是調用UnitySendMessage方法。 您可以在Java代碼中調用此方法,並將消息發送到C#,這樣您就可以獲得在C#中執行的指定方法。

您可以在Unity場景中添加gameObject並創建一個包含這三種方法的MonoBehavior腳本(paySucess(字符串消息),payFailed(字符串消息)和payCancel(消息))。 然后將新創建的腳本附加到gameObject(讓我們假設此gameObject的名稱為“PayListener”)並確保執行Java代碼時場景中存在gameObject(您可以在Awake調用DontDestroyOnLoad上的DontDestroyOnLoad,例如)。

然后,在您的Java代碼中,只需編寫如下:

EgamePay.pay(thisActivity, payAlias, new EgamePayListener() {
    @Override
    public void paySuccess(String alias) {
        com.unity3d.player.UnityPlayer.UnitySendMessage("PayListener","paySuccess", alias);
    }

    @Override
    public void payFailed(String alias, int errorInt) {
        com.unity3d.player.UnityPlayer.UnitySendMessage("PayListener","payFailed", alias + "#" + errorInt);
    }

    @Override
    public void payCancel(String alias) {
        com.unity3d.player.UnityPlayer.UnitySendMessage("PayListener","payCancel", alias);
    }
});

如果沒有com.unity3d.player.UnityPlayer類,它將阻止java文件成功構建。 您可以找到/Applications/Unity/Unity.app/Contents/PlaybackEngines/AndroidPlayer/bin/classes.jar文件,並將其添加為Java項目的依賴庫。 然后,您可以無錯誤地構建,生成和使用新的jar文件。

由於UnitySendMessage方法只能使用1個參數,因此您可能必須通過策略連接payFailed結果別名和errorInt,並在Unity C#側解析它。

通過使用新構建的jar文件並將其加載為AndroidJavaClassAndroidJavaObject ,當調用Java中的那個時,應調用PayListener腳本中的相應方法。

對於Android插件與UnitySendMessage的文檔,你可以參觀如何實現一個Android的JNI插件的官方指南這里 ,在具體例3。

看看http://jni4net.sourceforge.net/ 我已成功使用它在CLR和JVM之間進行通信。 可以在此處找到調用.NET類的Java應用程序示例。 還支持事件(綁定到java偵聽器接口)。

我自己最終解決了這個問題,其他答案在這里發布了,但不幸的是沒有解決我面臨的問題是在Unity中。

我解決它的方法是在Java中使用'GetResult'函數編寫一個自定義偵聽器類,該函數返回一個字符串,解釋結果是什么(即調用了哪個函數以及結果是什么)以及C#調用的結果的get函數通過AndroidJNI。

在進行購買調用之后,需要從C#調用get函數,直到我得到結果。

聽起來像一團糟。 你想要完成什么,為什么? 為什么不單獨運行JVM和單獨運行CLR,通過REST調用或類似的方式進行接口?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM