通过C#实现AndroidJavaObject在Unity中的奇怪行为

时间:2016-03-05 06:34:24

标签: unity3d unity5

相当长的帖子。它相当复杂,需要曾经使用过Unity插件的人(创建它们,而不是使用它们),并且我不希望因为一些常见的搜索词出现而被投票。所以,请阅读整篇文章。

所以,当我尝试通过Unity AndroidJavaObject

调用本机函数时,我发现了一个相当奇怪的问题。

我之前已经构建了本机插件,我尝试删除每次需要更新插件时必须更新多个JAR的依赖关系。所以,我将很多原生Java代码从插件转移到Unity本身。

具体来说,有一种直接从C#调用原生Android功能(即系统功能)的方法,而不是在调用本机函数的插件中创建插件和调用函数。

例如,早些时候,如果我必须创建Toast,我必须用Java编写一些本机代码,导出插件然后调用该函数。这些天,人们可以直接从C#调用Toast.makeText,如下所示。

以下是我如何致电Toast。

    public static void Toast (string text, int duration) {
        #if UNITY_ANDROID && !UNITY_EDITOR
        CreateActivity();

        activity.Call("runOnUiThread", new AndroidJavaRunnable ( () => {
            new AndroidJavaObject("android.widget.Toast", activity)
                .CallStatic<AndroidJavaObject>("makeText", activity, text, duration)
                    .Call("show");
        }) );
        #endif
    }

这里是CreateActivity方法

private static void CreateActivity () {
    #if UNITY_ANDROID && !UNITY_EDITOR
    if(activity == null)
        activity = new AndroidJavaClass("com.unity3d.player.UnityPlayer").
            GetStatic<AndroidJavaObject>("currentActivity");
    #endif

}

这完美无缺。但是,当我尝试使用相同的方法创建AlertDialog时,我得到一个 androidjavaexception java.lang.classnotfoundexception

这是相关代码

public static void ShowAlert (string title, string message, string buttonText) {

    #if UNITY_ANDROID && !UNITY_EDITOR

    CreateActivity();

    activity.Call("runOnUiThread", new AndroidJavaRunnable ( () => {
        var builder = new AndroidJavaObject("android.app.AlertDialog.Builder", activity);
        ***//Exception happens in the above line***

        builder.Call<AndroidJavaObject>("setMessage", message)  
            .Call<AndroidJavaObject>("setTitle", title)
                .Call<AndroidJavaObject>("setCancelable", false)
                .Call<AndroidJavaObject>("setNeutralButton", buttonText)
                .Call("show");
    }) );
    #endif
}

我尝试了什么

  1. 使用 android.support.v7.app.AlertDialog.Builder 而不是 android.app.AlertDialog.Builder
  2. 为v7&amp;添加了支持JAR。 v4(特别是 android-support-v4 &amp; android-support-v7-appcompat
  3. 尝试为Unity的JNI创建自己的实现并调用
  4. 以上都失败了。 (第三个,相当壮观)

    现在,我也尝试了其他类,其中大多数都工作(例如ProgressDialog,这是AlertDialog的子类),这些工作!

    此时,我感到很难过,我无法想到某些功能有效的有效理由,而其他功能则失败。

    任何想法都表示赞赏。

    编辑1:添加了LogCat

    I/Unity: AndroidJavaException: java.lang.ClassNotFoundException: android.app.AlertDialog.Builder
                                                at UnityEngine.AndroidJNISafe.CheckException () [0x00000] in <filename unknown>:0 
                                                at UnityEngine.AndroidJNISafe.CallStaticObjectMethod (IntPtr clazz, IntPtr methodID, UnityEngine.jvalue[] args) [0x00000] in <filename unknown>:0 
                                                at UnityEngine.AndroidJavaObject._CallStatic[AndroidJavaObject] (System.String methodName, System.Object[] args) [0x00000] in <filename unknown>:0 
                                                at UnityEngine.AndroidJavaObject.CallStatic[AndroidJavaObject] (System.String methodName, System.Object[] args) [0x00000] in <filename unknown>:0 
                                                at UnityEngine.AndroidJavaObject.FindClass (System.String name) [0x00000] in <filename unknown>:0 
                                                at UnityEngine.AndroidJavaObject._AndroidJavaObject (System.String className, System.Object[] args) [0x00000] in <filename unknown>:0 
                                                at UnityEngine.AndroidJavaObject..ctor (System.String className, System.Object[] args) [0x00000] in <filename unknown>:0 
                                                at AndroidNative+<ShowAlert>c__AnonSto
    

1 个答案:

答案 0 :(得分:3)

您遇到的问题是AlertDialog.Builder是AlertDialog的嵌套类,并且通过反射创建嵌套类(这是AndroidJavaObject尝试做的事情)需要稍微不同的语法在Java中:

android.app.AlertDialog$Builder

您的代码中还有其他一些小错误(您无法了解,因为您的构造函数不起作用):

  • setNeutralButton需要一个回调参数(可以为null)
  • 必须在AlertDialog本身上调用
  • show,而不是在构建器上调用。

考虑到这些微小的修正,工作代码示例如下所示:

public static void ShowAlert(string title, string message, string buttonText)
{
    CreateActivity();

    activity.Call("runOnUiThread", new AndroidJavaRunnable(() =>
    {
        var builder = new AndroidJavaObject("android.app.AlertDialog$Builder", activity);

        builder.Call<AndroidJavaObject>("setMessage", message)
            .Call<AndroidJavaObject>("setTitle", title)
                .Call<AndroidJavaObject>("setCancelable", false)
                .Call<AndroidJavaObject>("setNeutralButton", buttonText, null)
                .Call<AndroidJavaObject>("create")
                .Call("show");
    }));
}