Rufen Sie nicht statische Methoden für benutzerdefinierte Unity Android-Plugins auf

8

Ich versuche zu verstehen, wie ich meine eigenen Android-Plugins für Android erstelle.

Ich kann statische Methoden in meiner Java-Klasse (die in AndroidStudio erstellt wurde) aufrufen, aber ich kann wirklich keine nicht statischen Methoden aufrufen.

Ich überprüfe diese Links:

Aber keiner funktioniert.

Ich versuche, den Anruf über eine Schaltfläche von Unity zu erhalten, z. B.:

AndroidJavaClass UnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject currentActivity = UnityPlayer.Get<AndroidJavaObject>("currentActivity");
currentActivity.Call("SayHi");

Und meine Aktivität auf Android sieht so aus:

public class MainActivity extends UnityPlayerActivity {
    private static final String TAG = "LibraryTest";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "Created!");
    }

    public void SayHi()
    {
        Log.d(TAG, "HI_");
    }
}

Mein ADB wirft diese Nachricht: Geben Sie hier die Bildbeschreibung ein

Ich habe auch versucht, anstelle von UnityPlayer Folgendes aufzurufen:

AndroidJavaClass pluginClass = new AndroidJavaClass("com.example.eric.librarytest.MainActivity");

EDIT: Dies ist meine AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.eric.librarytest"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="24"
        android:targetSdkVersion="28" />

    <application android:label="@string/app_name" >
        <activity
            android:name="com.example.eric.librarytest.MainActivity"
            android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Aber funktioniert es auch nicht für nicht statische Methoden, es funktioniert nur für statische Methoden, wenn ich das tue pluginClass.CallStatic(""), eine Idee?

EDIT 2:

  • Taras Leskiv schlägt vor, UnityPlayer.Get in UnityPlayer.GetStatic zu ändern, aber dann erhalte ich den folgenden Fehler:

    Fehler: java.lang.NoSuchMethodError: Keine nicht statische Methode mit dem Namen = 'SayHi' Signatur = '() V' in der Klasse Ljava.lang.Object;

  • Proguard ist nicht aktiv.
Lotan
quelle
Können Sie Ihre AndroidManifest.xml hinzufügen? Haben Sie die MainActivity im Inneren?
JeanLuc
@ JeanLuc hat dem Beitrag hinzugefügt, und ja, es ist drinnen, wie Sie sehen können :(
Lotan
Ist es tatsächlich Ihre Aktivität zurückgegeben? Wenn ja, weiß Unity möglicherweise nichts über diesen Typ und denkt, dass es ein ist Activity. Vielleicht müssen Sie es irgendwie besetzen.
Bis zum
@tynn das war Jean Bouvattiers Antwort, aber es erklärt nicht, wie man diese Besetzung erreicht.
Lotan

Antworten:

1

Wenn Sie dies tun:

AndroidJavaClass UnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject currentActivity = UnityPlayer.Get<AndroidJavaObject>("currentActivity");
currentActivity.Call("SayHi");

Es funktioniert nicht, weil das currentActivityFeld statisch ist. Was Sie tun sollten, ist:

AndroidJavaClass UnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject currentActivity = UnityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
currentActivity.Call("SayHi");

Beachten Sie den Teil UnityPlayer.GetStatic

Hier ist ein weiterer Convenience-Ausschnitt aus einem meiner Plugins:

    static AndroidJavaObject _activity;

    public static AndroidJavaObject Activity
    {
        get
        {
            if (_activity == null)
            {
                var unityPlayer = new AndroidJavaClass(C.ComUnity3DPlayerUnityPlayer);
                _activity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
            }
            return _activity;
        }
    }
Taras Leskiv
quelle
Dann erhalte ich den folgenden Fehler: java.lang.NoSuchMethodError: Keine nicht statische Methode mit dem Namen = 'SayHi' Signatur = '() V' in der Klasse Ljava.lang.Object; :(
Lotan
Okay, das ist der nächste Fehler. Überprüfen Sie möglicherweise auch, ob Sie Proguad aktiviert haben, da es den Java-Code beim Erstellen verschleiern kann
Taras Leskiv
Nein, Proguard ist deaktiviert, weil ich kein Proguard-Verzeichnis habe. Was könnte es sonst noch sein?
Lotan
Ich verwende auch app-debug.aar anstelle von release, um sicherzugehen, dass Proguard keine Verkleinerung vornimmt.
Lotan
0

Vielleicht hat es mit der Java-Vererbung zu tun: Ihr currentActivity AndroidJavaObject ist von Klasse, com.unity3d.player.UnityPlayer aber diese Klasse hat keine SayHiMethode. Sie sollten Ihr Objekt umwandeln , MainActivitybevor Sie Ihre Methode aufrufen.

Jean Bouvattier
quelle
MainActivity ist aber auch eine AndroidJavaClass. Wie würden Sie das machen? Können Sie bitte ein Beispiel posten?
Lotan
Ich kann Ihnen jetzt nicht mehr helfen, aber dieser Link wird Ihnen wahrscheinlich helfen: devua.co/2016/07/30/…
Jean Bouvattier
Ich habe den Link ausprobiert, funktioniert aber nicht. Vielleicht mache ich etwas falsch mit der Besetzung? oO
Lotan
0

Mein Code war korrekt, das Problem war die Projektstruktur.

Mein Projekt war wie folgt:

Assets
├── Plugins
   ├── classes.jar

Und sollte sein wie:

Assets
├── Plugins
   ├── Android
      ├── classes.jar

Wurde obvius (nicht für mich) verursacht, dass der Fehler Spam die Nachricht war, die die Signatur nicht finden konnte, so dass die Software diese Klassen nicht lesen kann.

Lotan
quelle
-1

Sie müssen lediglich Ihren eigenen statischen Kontext in der Aktivitätsklasse deklarieren:

public class MainActivity extends UnityPlayerActivity {
    private static final String TAG = "LibraryTest";
    public static Context mContext;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContext = this;
        Log.d(TAG, "Created!");
    }

    public void SayHi()
    {
        Log.d(TAG, "HI_");
    }
}

Rufen Sie dann einfach eine nicht statische Methode aus C # wie folgt auf:

public static void AndroidCallFunction()
{
    using (AndroidJavaClass javaClass = new AndroidJavaClass("com.example.eric.librarytest.MainActivity"))
    {
        using (AndroidJavaObject activity = javaClass.GetStatic<AndroidJavaObject>("mContext"))
        {
            activity.Call("SayHi");
        }
    }
}

Es gibt KEINE anderen Methoden, um Methoden direkt aus Java-Code aufzurufen. Sie können Ihr eigenes Nachrichtensystem mit den Befehlen AndroidJavaProxy und Broadcast implementieren, ohne überhaupt aktiv zu sein. Dies ist jedoch eine andere Frage.

Nikolay Gonza
quelle
Dieser Ansatz (statische Kontextfelder) verursacht einen Speicherverlust.
0xBFE1A8
Ja, aber wenn es zu viele statische Felder gibt, ist dies gemacht, um zu verstehen, wie Ajo funktioniert
Nikolay Gonza
Eine statische Referenz ist überhaupt keine Option. Zunächst wissen Sie nicht, wie viele dieser Aktivitäten im Stapel landen. Wenn Sie es wirklich tun müssen, stellen Sie sicher, dass Sie nach sich selbst aufräumen onDestroy.
3.
Sie haben nur eine Aktivität, die den Unity-Player implementiert. Für andere Dinge (z. B. Dienste, andere Aktivitäten) können Sie immer Broadcasts verwenden. Dies ist eine sehr einfache und klassische Lösung
Nikolay Gonza
Entschuldigung für die späte Antwort @NikolayGonza, aber mit Ihrem Code ist die Aktivität Null :(
Lotan