KotlinでUnity用のAndroid pluginを作成する方法

KotlinでUnity用のAndroid pluginを作成するときの手順をまとめました。

# 開発環境
- Unity 2017.4.2f2
- AndroidStudio 3.1.2
- Kotlin 1.2.41

# AARの作成
### プロジェクトの作成
1. AndroidStudioを起動して空のプロジェクトを作成する
2. File -> New -> New Module -> Android Libraryで空のモジュールを作成する
3. UnityPlayerActivityを継承するために、Unity付属のclasses.jarを作成したモジュールのlibs/に追加する。classes.jarの場所は下記マニュアルを参照

引用: [UnityPlayerActivity Java コードの拡張](https://docs.unity3d.com/ja/current/Manual/AndroidUnityPlayerActivity.html)
> UnityPlayerActivity を拡張するには、Unity に付属の classes.jar を見付けてください。これは、インストールフォルダー（通常 C:\Program Files\Unity\Editor\Data [Windows] または /Applications/Unity [Mac]） のサブフォルダーである PlaybackEngines/AndroidPlayer/Variations/mono または il2cpp/Development or Release/Classes/ 内にあります。

### build.gradleを編集する
compileOnlyでコンパイル時のみUnityのライブラリを使用し、AARを作成する時は除外します。

```gradle:build.gradle
dependencies {
    compileOnly fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    // 以下省略 
}
```
UnityPlayerActivityを継承したクラスを作成します。今回はUnity側のScriptからプラグインに実装したreceive関数を呼び出し、コールバックを受け取ります。

```kotlin:OverrideActivity.kt
class OverrideActivity: UnityPlayerActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Toast.makeText(this, "Start!", Toast.LENGTH_LONG).show()
    }

    // Unity側から呼び出される関数
    fun receive() {
        // Unity側のスクリプトのonCallBack関数を呼び出す
        // 第一引数はアタッチされたGameObjectの名前と同じにする
        UnitySendMessage("gameObject", "onCallBack", "hogehoge")
    }
}
```
terminalで`./gradlew :<library name>:assembleRelease`を実行します。ビルドに成功するとプロジェクトの`<library name>/build/outputs/aar/`にaarが作成されているので、Unityのプロジェクトの`/Assets/Plugins/Android/`に追加します。

# Unityで作成したプラグインを使用する
### kotlin-runtime.jarを追加する
Kotlinで作成したプラグインをUnityで実行するにはkotlin-runtime.jarをプロジェクトに追加する必要があります。追加しなかった場合は、NoClassDefFoundErrorがスローされてアプリがクラッシュします。kotlin-runtime.jarは[Kotlin公式リポジトリ](https://github.com/JetBrains/kotlin/releases/)のkotlin-compiler-x.x.x.zipの中に入っているので、プラグイン作成時に使用したKotlinと同じバージョンのファイルをダウンロードして解凍し、`/Assets/Plugins/Android/`に追加します。
### プラグインを呼び出す
Unityのプロジェクトの`/Assets/Plugins/Android/`にAndroidManifest.xmlを追加し、android:name属性を変更します。

```xml:AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.unity3d.player"
    xmlns:tools="http://schemas.android.com/tools"
    android:installLocation="preferExternal"
    android:versionCode="1"
    android:versionName="1.0">
    <supports-screens
        android:smallScreens="true"
        android:normalScreens="true"
        android:largeScreens="true"
        android:xlargeScreens="true"
        android:anyDensity="true"/>

    <application
        android:theme="@style/UnityThemeSelector"
        android:icon="@drawable/app_icon"
        android:label="@string/app_name">
        <activity android:name="com.example.unity.OverrideActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
        </activity>
    </application>
</manifest>
```

次に、Unity側のScriptでプラグインを呼び出す処理を追加します。

```c#:CallPlugin.cs
public class CallPlugin : MonoBehaviour {
	private AndroidJavaObject plugin;

	void Start () {
		plugin = new AndroidJavaObject ("com.example.unity.OverrideActivity");
	}
	
	void Update () {
		plugin.Call ("receive");
	}

	public void onCallBack(string message) {
		Debug.Log (message);
	}
}
```

# 実行
アプリの実行時にToastが表示され、Logcatに"hogehoge"と表示されていたら成功です。