Я нативный разработчик и новичок в Unity. Я пытаюсь использовать свои сильные стороны, кодируя на Kotlin, а затем используя свой код в качестве плагина в Unity. Одна проблема, с которой я сталкиваюсь, заключается в том, что я не могу понять, как ссылаться на функцию, которая находится внутри объекта-компаньона.
Вот мой класс Котлина
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
)
}
}
}
Я хочу иметь доступ к функции factory
из моего кода Unity.
В Котлине я могу сделать так,
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: нет статического метода с именем = 'фабрика' подпись = '(Landroid.app.Application;) Ljava/lang/Object;' в классе Ljava.lang.Object; 12-10 14:00:21.883 13537 13674 E Unity: java.lang.NoSuchMethodError: нет статического метода с именем = 'фабрика' подпись = '(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: в com.unity3d.player.UnityPlayer.nativeRender (собственный метод) 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: в com.unity3d.player.UnityPlayer$e$1.handleMessage(Неизвестный источник: 95) 12-10 14:00:21.883 13537 13674 E Unity: в android.os.Handler.dispatchMessage(Handler.java:103) 12-10 14:00:21.883 13537 13674 E Unity: на android.os.Looper.loop(Looper.java:214) 12-10 14:00:21.883 13537 13674 E Unity: в com.unity3d.player.UnityPlayer$e.run(Неизвестный источник: 20)
Чтобы понять, что не так с вашей реализацией, вам нужно декомпилировать ваш код Kotlin
в код Java
и реализовать часть Unity
на основе кода Java
, а не Kotlin
.
Давайте рассмотрим простой пример кода 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, опубликовать его здесь, чтобы мы могли понять, почему он не работает.