Llame a métodos no estáticos en complementos personalizados de Unity Android

8

Estoy tratando de entender cómo construir mis propios complementos de Android para Android.

Logro llamar a métodos estáticos en mi clase Java (la creada en AndroidStudio), pero realmente NO PUEDO llamar a métodos no estáticos.

Reviso esos enlaces:

Pero ninguno funciona.

Estoy tratando de recibir la llamada de un botón de Unity como:

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

Y mi actividad en Android se ve así:

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

Mi ADB está lanzando este mensaje: ingrese la descripción de la imagen aquí

También he intentado llamar en lugar de UnityPlayer llamarlo así:

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

EDITAR: Este es mi 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>

Pero tampoco funciona para métodos no estáticos, solo funciona para métodos estáticos si lo hago pluginClass.CallStatic(""), ¿alguna idea?

EDITAR 2:

  • Taras Leskiv sugiere cambiar UnityPlayer.Get a UnityPlayer.GetStatic, pero luego aparece el siguiente error:

    error: java.lang.NoSuchMethodError: ningún método no estático con nombre = 'SayHi' firma = '() V' en la clase Ljava.lang.Object;

  • Proguard no está activo.
Lotan
fuente
¿Puedes agregar tu AndroidManifest.xml? ¿Tienes la MainActivity adentro?
JeanLuc
@JeanLuc agregó a la publicación, y sí, está adentro como puedes ver :(
Lotan
¿Es realmente tu actividad devuelta? Si es así, Unity podría no saber sobre ese tipo y piensa que es un Activity. Por lo tanto, es posible que deba lanzarlo de alguna manera.
tynn
@tynn esa fue la respuesta de Jean Bouvattier, pero no explica cómo lograr este reparto.
Lotan

Respuestas:

1

Cuando haces esto:

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

No funciona porque el currentActivitycampo es estático, lo que debe hacer es:

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

Observe la parte UnityPlayer.GetStatic

Aquí hay otro fragmento de conveniencia de uno de mis complementos:

    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
fuente
Luego obtengo el siguiente error: java.lang.NoSuchMethodError: ningún método no estático con name = 'SayHi' signature = '() V' en la clase Ljava.lang.Object; :(
Lotan
De acuerdo, ese es el siguiente error, tal vez también verifique si tiene habilitado proguad ya que puede ofuscar el código de Java en la compilación
Taras Leskiv
No, proguard está deshabilitado porque no tengo el directorio proguard, ¿qué más podría ser?
Lotán
También estoy usando app-debug.aar en lugar de liberarlo, para asegurarme de que Proguard no realice ninguna reducción.
Lotan
0

Tal vez tenga que ver con la herencia de Java: su CurrentActivity AndroidJavaObject es de clase com.unity3d.player.UnityPlayer pero esta clase no tiene SayHimétodo, debe lanzar su objeto MainActivityantes de llamar a su método.

Jean Bouvattier
fuente
Pero MainActivity también es un AndroidJavaClass, ¿cómo lo harías? ¿Puedes publicar un ejemplo por favor?
Lotan
No puedo ayudarte más ahora, pero este enlace probablemente te ayudará: devua.co/2016/07/30/…
Jean Bouvattier
He probado el enlace pero no funciona, ¿tal vez estoy haciendo algo mal con el elenco? oO
Lotan
0

Mi código era correcto, el problema era la estructura del proyecto.

Mi proyecto fue como:

Assets
├── Plugins
   ├── classes.jar

Y debería ser como:

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

¿Obvius (no para mí) causó el error spam del mensaje que no pudo encontrar la firma, por lo que el software no puede leer esas clases?

Lotan
fuente
-1

Todo lo que necesita hacer es declarar su propio contexto estático en la clase de actividad:

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

Y luego simplemente llame a cualquier método no estático desde C # como este:

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

Hay NO otros métodos para llamar a métodos directamente desde el código de Java. Puede implementar su propio sistema de mensajería utilizando los comandos AndroidJavaProxy y Broadcast sin siquiera actividad, pero es otra pregunta.

Nikolay Gonza
fuente
Este enfoque (campos de contexto estáticos) causa pérdida de memoria.
0xBFE1A8
Sí, pero si hay demasiados campos estáticos, esto se hace para no entender cómo funciona ajo
Nikolay Gonza
Una referencia estática no es una opción en absoluto. Primero, no sabes cuántas de estas actividades terminan en la pila. Si realmente necesita hacerlo, asegúrese de limpiar después de entrar onDestroy.
tynn
Solo tiene 1 actividad que implementa la unidad player, para otras cosas (por ejemplo, servicios, otras actividades) siempre puede usar transmisiones. Esta es una solución muy simple y clásica
Nikolay Gonza
lo siento por la respuesta tardía @NikolayGonza, pero con su código, la actividad es nula :(
Lotan