Android плагин для Unity3D

Зачем вам нужен плагин.

В принципе не нужен, а мне вот очень хочется. Я хочу чтобы в Unity тосты появлялись. Или я хочу биллинг необычный встроить в свою игру Unity. Начнем!

Ранее я уже делал плагин для Unity и надо сказать довольно успешно. Делается это с помощью практики наследования активити UnityPlayerActivity. Официальный мануал

Создаем Android Java Library, получаем aar файл, внутри aar находим classes.jar и записываем в папку с Unity проектом /Assets/Plugins/Android/classes.jar

Да чтобы получить UnityPlayerActivity нам нужно в папку /libs добавить библиотеку classes.jar из Unity, у меня он расположен по такому пути: C:\Program Files\Unity\Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Release\Classes\

package com.company.product;
import com.unity3d.player.UnityPlayerActivity;
import android.os.Bundle;
import android.util.Log;

public class OverrideExample extends UnityPlayerActivity {

  protected void onCreate(Bundle savedInstanceState) {
    // call UnityPlayerActivity.onCreate()
    super.onCreate(savedInstanceState);
    // print debug message to logcat
    Log.d("OverrideActivity", "onCreate called!");
  }

  public void foo() {
    //body your function
  }
} 

Добавляем наш активити в Manifest.xml как основной активити OverrideExample. И кладем этот манифест в туже папку /Assets/Plugins/Android/Manifest.xml

Теперь в нашем скрипте пишем

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AndroidGPInappScript : MonoBehaviour
{
  AndroidJavaClass javaUnityPlayer;
  AndroidJavaObject currentActivity;

  void Start()
  {
    if (Application.platform == RuntimePlatform.Android)
    {
      javaUnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
      currentActivity = javaUnityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
    }
  }

  void Foo() 
  {
    if (Application.platform == RuntimePlatform.Android)
      {
        currentActivity.Call("foo");
      }
  }
}

В том что я написал выше - нет ничего необычного, или сложного. Но практика наследования плагина ИМХО является не лучшим вариантом. Есть способ лучше.

Я прочитал эту статью и вдохновился ею.

Так о чем там написано много букв. О том что можно не наследовать активити, а добавлять на активити свой Fragment. Тогда ваша библиотека не будет требовать указания в Manifest.xml, и значит не будет проблемы двух библиотек, обе которых наследуют UnityPlayerActivity.

Как же это сделать. Значит в нашей библиотеке пишем такой код

package com.company.product;
import com.unity3d.player.UnityPlayerActivity;
import android.os.Bundle;
import android.util.Log;

public class OverrideExample extends Fragment {
  public static OverrideExample instance;

  public static void startFragment() {
    instance = new OverrideExample();
UnityPlayer.currentActivity.getFragmentManager().beginTransaction().add(instance, "OverrideExample").commit();
  }

  public void foo() {
    //body your function
  }
} 

А скрипт в Unity получается таким:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AndroidGPInappScript : MonoBehaviour
{
  AndroidJavaClass javaOverrideExampleClass;
  AndroidJavaObject javaOverrideExampleInstance;

  void Start()
  {
    if (Application.platform == RuntimePlatform.Android)
    {
      javaOverrideExampleClass = new AndroidJavaClass("com.company.product.OverrideExample");
      javaOverrideExampleClass.CallStatic("startFragment");
      javaOverrideExampleInstance = javaOverrideExampleClass .GetStatic<AndroidJavaObject>("instance");
    }
  }

  void Foo() 
  {
    if (Application.platform == RuntimePlatform.Android)
      {
        javaOverrideExampleInstance.Call("foo");
      }
  }
}

А вы спросите, а зачем вообще этот активити сдался. Вот это правильный вопрос. Активити нафиг не сдался. Все это делалось ради того, чтобы получить собственный public void onActivityResult(int requestCode, int resultCode, Intent data), для обработки например результата вызова startActivityForResult (Intent intent, int requestCode). Просто если у вас нет активити, то у вас нет и результата.

И напоследок еще один важный момент. Если нужно передать данные из Android плагина в Unity, следует воспользоваться вот такой шикарной функцией, где methodName это функция в Unity, а gameObjectName это имя объекта, к которому ваш скрипт Unity добавлен. В общем это просто реализация вот этой функции

void SendUnityMessage(String methodName, String parameter) {
    UnityPlayer.UnitySendMessage(gameObjectName, methodName, parameter);
}