突然仕事でUnity向けのSDKやPluginを作ることになった人向け資料<Android実践編>

# はじめに
Android JavaでのUnity Pluginを作成をまとめました。
ツールは以下のバージョンを使用しています。
他のバージョンでも大丈夫だと思いますがaarを扱うためUnity5以上を対象としています。

 - macOS 10.12
 - Unity 5.3.4
 - Android Studio 2.2.3

なぜこの記事を書こうと思ったかというと書籍などではAndroid Pluginの項は大体Toast表示等で終わってしまうからです..
(Unity→Androidの呼び出しのみ)
今回はUnityからAndroidのソースを呼び出しコールバックを受け取るところまで行います。
(Unity→Android, Android→Unityの呼び出し)

さりげなく[前回の記事](http://qiita.com/keidroid/items/a513598bfcd718defb6a)から9ヶ月越しの続編です。

以下の順序で説明します。

 - 1 開発方法について
  - 1.1 aarの作成について(AndroidStudio)
  - 1.2 Unityのaar組み込みについて(Unity)
 - 2 ソースコードについて
  - 2.1 Unity→Androidの呼び出しソースコードについて(Unity)
  - 2.2 Android→Unityの呼び出しソースコード(AndroidStudio)
 - 3 Tips

# 1 開発方法について
## 1.1 aarの作成について(AndroidStudio)

Androidで適当なプロジェクトを作成し、New ModuleでAndroid Libraryを指定します。

<img width="1082" alt="スクリーンショット 2017-02-28 1.32.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/19692/4aba2b01-b4af-f267-b6e5-8d7139a50845.png">

Moduleのlibsフォルダにunityのclasses.jarを追加します。(ここではunity5.3.4-classes.jarにrenameしました)
classes.jarの場所は以下Unityマニュアルに書いてあります。

<img width="1105" alt="スクリーンショット 2017-02-28 1.37.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/19692/83c3464a-01de-0df3-ac8b-9cce41f7ff3c.png">

引用) UnityPlayerActivity Java コードの拡張
https://docs.unity3d.com/ja/current/Manual/PluginsForAndroid.html

> まず Unity/Android に付属している classes.jar を探します。このファイルは Unity をインストールしたフォルダー（Windows であれば C:\Program Files\Unity\Editor\Data 、MacOSX であれば /Applications/Unity ）のサブフォルダー PlaybackEngines/AndroidPlayer/Variations/mono または il2cpp/Development or Release/Classes/ にあります。

classes.jarを追加しSyncをおこなうとUnityのクラスが使用可能になります↓

<img width="1033" alt="スクリーンショット 2017-02-28 1.41.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/19692/f7754ef4-1522-3d81-afa6-ed1efcb76347.png">


ビルド時にunityのclasses.jarは作成するaarから外すようにします。
unityのclasses.jarを外さないとunityでAndroid向けビルドを行ったときにunityのclasses.jarが重複となりビルドに失敗します。

``` build.gradle
android.libraryVariants.all { variant ->
    variant.outputs.each { output ->
        output.packageLibrary.exclude('libs/unity5.3.4-classes.jar')
    }
}
```

上記でUnity向けAndroidライブラリ作成の準備は完了です。
AndroidStudioのメニュー > Build > Make Module
を選択するとaarが作成されます。

この時、Proguardの設定にご注意ください。
Proguardでメソッド名やクラス名が変わるとUnityから呼び出す時にClassNotFoundExceptionになります。

## 1.2 Unityのaar組み込みについて(Unity)

1.1で作成したaarをAssets > Plugins > Androidにドラッグするだけです。

<img width="627" alt="スクリーンショット 2017-02-28 2.08.39.png" src="https://qiita-image-store.s3.amazonaws.com/0/19692/cb8eb691-443f-034d-1a2a-33abe91d0a60.png">

なぜこれだけで動作するのかというと、そういうunityの仕様のためです。
詳細は以下を見てください。

参考) Android ライブラリプロジェクト
https://docs.unity3d.com/ja/current/Manual/PluginsForAndroid.html
参考) 特殊なフォルダー名
https://docs.unity3d.com/jp/current/Manual/SpecialFolders.html

また、Activity追加や権限変更などでAndroidManifest.xmlを変更する場合、同じくAssets > Plugins > Androidに追加します。

引用) UnityPlayerActivity Java コードの拡張
https://docs.unity3d.com/ja/current/Manual/PluginsForAndroid.html

> 新しいAndroidManifest.xml を作成することも必要です。
AndroidManifest.xml ファイルも Assets->Plugins->Android フォルダーに配置する必要があります。（カスタムマニフェストを配置すると、デフォルトの Unity Android マニフェストを完全にオーバーライドします）。


〜〜

ここまでがPlugin作成と組み込み手順です！(とてもざっくり)
次は実際のコード呼び出し方法を説明します。

〜〜

# 2. ソースコードについて
## 2.1 Unity→Androidの呼び出しソースコードについて(Unity)

一番簡単な方法はAndroidJavaObject(AndroidJavaClass)の使用です
インスタンスであればAndroidJavaObject、インスタンス不要なクラスへのアクセスはAndroidJavaClassで使い分けます。
staticなメソッドであればCallStatic、通常のメソッドはCallを呼びます。
以下マニュアルにサンプルコードが掲載されています。

参考) AndroidJavaObject Call
https://docs.unity3d.com/ja/current/ScriptReference/AndroidJavaObject.Call.html

## 2.2 Android→Unityの呼び出しソースコード(AndroidStudio)

Android側からUnityの処理を呼び出すことが必要なケースがあります。
Android Java側でイベントハンドラをおこなう場合や
UnityがJavaのクラスを呼び出す際に非同期で値を返して欲しい場合などです。

上記のような場合はcom.unity3d.player.UnityPlayerクラスのUnitySendMessageメソッドを使用します。

``` java:Java側の処理
com.unity3d.player.UnityPlayer.UnitySendMessage(
    GameObjectName, //string ゲームオブジェクト名
    MethodName, //string メソッド名
    message //string 送信する値
);
```

以下マニュアルの通り、Unity側で対象のゲームオブジェクト内コンポーネントに以下形式でメソッドを定義する必要があります。
引数は文字列で1つのみなので複数データ送信はJSONなどに変換する必要があります。
複数人での開発の際はあらかじめインターフェイスを定義するのが良いと思います。

``` C#:C#
void MethodName(string message)
```

``` javascript:Javascript
function MethodName(message:string)
```

参考) ネイティブコードから C#/JavaScript をコールバックする
https://docs.unity3d.com/jp/current/Manual/PluginsForIOS.html

# 3 Tips
Android Java上でUI操作を扱う場合、UIスレッド以外から操作を行うとIllegalStateExceptionが発生します。
Unityから呼び出す処理でUI操作を行う場合は、以下のようにUIスレッドで行うようにしてください。

``` java:Java側の処理
import android.app.Activity;
import com.unity3d.player.UnityPlayer;

public void someUIAction() {
    final Activity activity = UnityPlayer.currentActivity;
    activity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
            //UI操作の処理
        }
    });
}
```

# まとめ
UnityからAndroid Javaの呼び出しはAndroidJavaObject, 逆はUnitySendMessageでという話でした。
つまづきどころ、環境構築もまとめたのでUnityでのAndroid Plugin開発は
// C++での開発などに手を出さなければ
上記で大体できるようになると思います。
参考になれば幸いです。