当通过 C# 实现时,Unity 中 AndroidJavaObject 的奇怪行为

Weird behaviour of AndroidJavaObject in Unity, when implemented through C#

post 相当长。它相当复杂,需要之前使用过 Unity 插件的人(创建它们,而不是使用它们)并且我不希望因为出现一些常见的搜索词而被否决。所以,请阅读整个 post。

所以,当我尝试通过 Unity 的 AndroidJavaObject

调用本机函数时,我遇到了一个相当奇怪的问题

我以前构建过本机插件,我试图消除每次需要更新插件时必须更新多个 JAR 的依赖。所以,我将很多原生 Java 代码从插件中移到 Unity 本身。

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

例如,早些时候,如果我必须直接从 C# 创建一个 Toast, I'd have to write some native code in Java, export the plugin and then call the function. These days, one can just call the Toast.makeText,如下所示。

以下是我如何打电话祝酒。

    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 和 v4 的支持 JAR(特别是 android-support-v4 & android-support-v7-应用程序兼容性)
  3. 尝试为 Unity 的 JNI 创建我自己的实现并调用它

以上都失败了。 (第三个,比较壮观)

现在,我也尝试了其他 类,其中大部分都有效(例如 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

您 运行 遇到的问题是 AlertDialog.Builder 是一个 嵌套的 class 的 AlertDialog,并创建嵌套的 classes 通过反射(这是 AndroidJavaObject 试图做的)在 Java:

中需要稍微不同的语法
android.app.AlertDialog$Builder

您的代码中还有其他一些小错误(您不知道是因为您的构造函数不工作):

  • setNeutralButton 需要回调参数(可以为空)
  • show 必须在 AlertDialog 本身上调用,而不是在生成器上调用。

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

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