【问题标题】:Unity: Call Android Kotlin Function Inside Companion Object from UnityUnity:从 Unity 调用 Companion 对象内部的 Android Kotlin 函数
【发布时间】:2020-12-11 18:15:04
【问题描述】:

我是一名本地开发人员,并且是 Unity 的新手。我试图通过在 Kotlin 中编码然后将我的代码用作 Unity 中的插件来发挥我的优势。我遇到的一个问题是我无法弄清楚如何引用伴随对象内部的函数。

这是我的 Kotlin 课程

class MyAnalytics internal constructor(
    private val MyAnalyticsConfiguration: MyAnalyticsConfiguration
) : MyAnalyticsLogger {

    .
    .
    .

    override fun logEvent(eventRequest: Event?) {
        // some code in here
    }

    companion object {

        @JvmStatic
        fun factory(
            context: Context,
            MyAnalyticsConfiguration: MyAnalyticsConfiguration = MyAnalyticsConfiguration()
        ) : MyAnalytics {
            val eventExecutor = MyWorkManager(
                workManager = WorkManager.getInstance(context.applicationContext),
                MyAnalyticsConfiguration = MyAnalyticsConfiguration
            )
            return MyAnalytics(
                MyAnalyticsConfiguration
            )
        }
    }
}

我希望能够从我的 Unity 代码中访问 factory 函数。

在 Kotlin 中我可以这样做,

MyAnalytics.factory(
      context = requireActivity()
)

但是我怎样才能在 Unity 中做同样的事情呢?这是我尝试过的。


AndroidJavaClass UnityPlayerClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject UnityPlayerActivity = UnityPlayerClass.GetStatic<AndroidJavaObject>("currentActivity");
AndroidJavaObject myAnalytics = new AndroidJavaObject("com.test.analytics.MyAnalytics");
AndroidJavaObject analyticsObject = myAnalytics.Call<AndroidJavaObject>("factory", UnityPlayerActivity); //Also tried with 'CallStatic'; no result, same error

我收到的错误是,

AndroidJavaException: java.lang.NoSuchMethodError: no static method with name='factory' signature='(Landroid.app.Application;)Ljava/lang/Object;'在类 Ljava.lang.Object 中; 12-10 14:00:21.883 13537 13674 E Unity: java.lang.NoSuchMethodError: no static method with name='factory' signature='(Landroid.app.Application;)Ljava/lang/Object;'在类 Ljava.lang.Object 中; 12-10 14:00:21.883 13537 13674 E Unity:在 com.unity3d.player.ReflectionHelper.getMethodID(未知来源:162) 12-10 14:00:21.883 13537 13674 E Unity : at com.unity3d.player.UnityPlayer.nativeRender(Native Method) 12-10 14:00:21.883 13537 13674 E Unity:在 com.unity3d.player.UnityPlayer.access$300(未知来源:0) 12-10 14:00:21.883 13537 13674 E Unity : at com.unity3d.player.UnityPlayer$e$1.handleMessage(未知来源:95) 12-10 14:00:21.883 13537 13674 E 统一:在 android.os.Handler.dispatchMessage(Handler.java:103) 12-10 14:00:21.883 13537 13674 E 统一:在 android.os.Looper.loop(Looper.java:214) 12-10 14:00:21.883 13537 13674 E Unity : at com.unity3d.player.UnityPlayer$e.run(Unknown Source:20)

【问题讨论】:

    标签: java android unity3d kotlin


    【解决方案1】:

    为了了解您的实现实际上有什么问题,您需要将Kotlin 代码反编译为Java 代码并基于Java 代码而不是Kotlin 实现Unity 部分。

    让我们有一个简单的Kotlin 代码示例,它将打印日志,仅此而已:

    class MyKotlinClass(val name: String = "DEFAULT NAME") {
        fun callNormalFunc() {
            Log.d("UNITY", "callNormalFunc from Kotlin code")
        }
        companion object {
            @JvmStatic
            fun callStaticCompanionFunc(): MyKotlinClass {
                Log.d("UNITY", "callStaticCompanionFunc from Kotlin code")
                return MyKotlinClass("NEW NAME")
            }
        }
    }
    

    反编译后的Java代码如下:

    public final class MyKotlinClass {
       @NotNull
       private final String name;
       @NotNull
       public static final MyKotlinClass.Companion Companion = new MyKotlinClass.Companion((DefaultConstructorMarker)null);
    
       public final void callNormalFunc() {
          Log.d("UNITY", "callNormalFunc from Kotlin code");
       }
    
       @NotNull
       public final String getName() {
          return this.name;
       }
    
       public MyKotlinClass(@NotNull String name) {
          Intrinsics.checkNotNullParameter(name, "name");
          super();
          this.name = name;
       }
    
       // $FF: synthetic method
       public MyKotlinClass(String var1, int var2, DefaultConstructorMarker var3) {
          if ((var2 & 1) != 0) {
             var1 = "DEFAULT NAME";
          }
    
          this(var1);
       }
    
       public MyKotlinClass() {
          this((String)null, 1, (DefaultConstructorMarker)null);
       }
    
       @JvmStatic
       @NotNull
       public static final MyKotlinClass callStaticCompanionFunc() {
          return Companion.callStaticCompanionFunc();
       }
    
       public static final class Companion {
          @JvmStatic
          @NotNull
          public final MyKotlinClass callStaticCompanionFunc() {
             Log.d("UNITY", "callStaticCompanionFunc from Kotlin code");
             return new MyKotlinClass("NEW NAME");
          }
    
          private Companion() {
          }
    
          // $FF: synthetic method
          public Companion(DefaultConstructorMarker $constructor_marker) {
             this();
          }
       }
    }
    

    从反编译的代码中我们可以看出,实际上我们可以通过两种方式调用标记为@JvmStatic的函数。首先直接来自我们的对象,其次使用Companion 对象。

    使用此调用的 Unity 代码如下所示:

    public class KotlinCallScript : MonoBehaviour {
    
        private AndroidJavaObject _object;
        private AndroidJavaClass _staticClass;
        // Start is called before the first frame update
        private void Start () {
            _object = new AndroidJavaObject ("com.hardartcore.kotlin.MyKotlinClass");
            _staticClass = new AndroidJavaClass ("com.hardartcore.kotlin.MyKotlinClass");
            var defaultName = _object.Call<string> ("getName");
            Debug.Log ("START GET DEFAUL NAME: " + defaultName);
        }
    
        public void CallNormalFunction () {
            _object.Call ("callNormalFunc");
        }
    
        public void CallStaticFunction () {
            var companionObject = _staticClass.GetStatic<AndroidJavaObject> ("Companion");
            var newName = companionObject.Call<AndroidJavaObject> ("callStaticCompanionFunc").Call<string> ("getName");
            Debug.Log ("CALL STATIC FUNCTION NEW NAME: " + newName);
        }
    
        public void CallSecondWay () {
            var kotlinObject = _object.CallStatic<AndroidJavaObject> ("callStaticCompanionFunc");
            var newName = kotlinObject.Call<string> ("getName");
            Debug.Log ("CALL SECOND WAY NEW NAME: " + newName);
        }
    
    }
    

    这取决于你喜欢哪种方式。

    我的建议是查看您反编译的 Java 代码,将其发布在这里,以便我们了解它为什么不起作用。

    【讨论】:

      猜你喜欢
      • 2015-02-17
      • 2012-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-11
      • 2023-01-06
      相关资源
      最近更新 更多