UnityのGradleビルドでPlayServicesResolverとおさらばする手順

案外情報が少なかった(特に日本語)ので調べたり試してみた。
Gradleのお話とか詳細な使い方は割愛。
(そもそも詳しくないので間違えてたらごめんなさい。。。)

前置き
----

- 使用するAndroidプラグインが増えてくると、Unity上でのPlayServicesプラグインの依存関係に悩まされることがある。
    - 巷ではUnityPlayServicesResolverを使うのがド定番
    - が、PlayServicesResolverでは複雑な依存関係を解決できないことがある。

### Unityのビルドシステム

公式の情報はこちら。
https://docs.unity3d.com/ja/current/Manual/android-BuildProcess.html

- Unityのビルドは「Internal」と「Gradle」の2つある。
    - 「Internal」はUnityが独自にAndroidSDK(のツール群)を使用して作る
        - 以前はこちらがデフォルトだった
    - 「Gradle」はGradleプロジェクトを出力してそいつで作る
        - Unity2017.3.0からこちらがデフォルトに変わったようです([こちらのリリースノート](https://unity3d.com/jp/unity/whats-new/unity-2017.3.0))
    - Gradleはネットワーク経由で必要なプラグインをDLしてビルドに含めることができる
        - ここでUnityPlayServicesResolverを使わずにPlayServicesプラグインを含めるのがこの記事の趣旨

Gradleビルドに必要な手順は主に2つです。

1. UnityのBuildSettingsからビルドシステムを「Gradle」に変える
2. mainTemplate.gradleファイルを用意する

UnityのBuildSettingsからビルドシステムを「Gradle」に変える
----

Unityエディタ上でマウスをカチカチするだけですね。
BuildSettingsのAndroid設定から「Build System」に「Gradle」の設定があります。

<img width="623" alt="image_build_system.png" src="https://qiita-image-store.s3.amazonaws.com/0/30406/08fa2c4c-144e-4f2d-0438-d477a44a2112.png">

Unity2017以降ならPlayerSettingsからも設定できるようです。

<img width="387" alt="image_player_setting_build_system.png" src="https://qiita-image-store.s3.amazonaws.com/0/30406/228a16d0-89cf-844c-4dcc-2d752a6c9dea.png">


Unity2017.3.0以降ならデフォルトで「Gradle」なのでこの手順は不要です。

バッチビルドなどでC#スクリプトから設定を変更したい場合は下記のエディタ拡張用コードを埋め込みます。

```csharp
EditorUserBuildSettings.androidBuildSystem = AndroidBuildSystem.Gradle;
```


mainTemplate.gradleファイルを用意する
----

Gradleプロジェクトにはbuild.gradleが必要です。
UnityはGradleプロジェクトを出力するときにUnityプロジェクトの構成からbuild.gradleを作成してくれます。

build.gradleの作成にはmainTemplate.gradleを使います。
このファイルはUnityエディタをインストールしたディレクトリ内の下記にあります。

```
PlaybackEngines/AndroidPlayer/Tools/GradleTemplates/mainTemplate.gradle
```

参考にUnity2017.4.10f1のmainTemplate.gradleを下記に掲載します。

ファイル内に「**」で挟まれた記述が含まれていますが、これはUnityがbuild.gradleを作成する際にUnityプロジェクトの各情報に置き換えるための目印のようです。

```gradle
// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN
buildscript {
	repositories {
		jcenter()
	}

	dependencies {
		classpath 'com.android.tools.build:gradle:2.3.0'
	}
}

allprojects {
   repositories {
      flatDir {
        dirs 'libs'
      }
   }
}

apply plugin: 'com.android.application'

dependencies {
	compile fileTree(dir: 'libs', include: ['*.jar'])
**DEPS**}

android {
	compileSdkVersion **APIVERSION**
	buildToolsVersion '**BUILDTOOLS**'

	defaultConfig {
		targetSdkVersion **TARGETSDKVERSION**
		applicationId '**APPLICATIONID**'
		ndk {
            abiFilters **ABIFILTERS**
        }
	}

	lintOptions {
		abortOnError false
	}

	aaptOptions {
		noCompress '.unity3d', '.ress', '.resource', '.obb'**STREAMING_ASSETS**
	}

**SIGN**
	buildTypes {
  		debug {
 			minifyEnabled **MINIFY_DEBUG**
 			useProguard **PROGUARD_DEBUG**
 			proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-unity.txt'**USER_PROGUARD**
  			jniDebuggable true
  		}
  		release {
 			minifyEnabled **MINIFY_RELEASE**
 			useProguard **PROGUARD_RELEASE**
  			proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-unity.txt'**USER_PROGUARD**
  			**SIGNCONFIG**
  		}
	}

}
```

このmainTemplate.gradleはプロジェクトごとにカスタマイズしたものを使うこともできます。

Unityプロジェクトの「Assets/Plugins/Android/mainTemplate.gradle」にファイルをコピーして配置してください。
「Assets/Plugins/Android/mainTemplate.gradle」にファイルがある場合はPlaybackEnginesのmainTemplate.gradleを使わずに、こちらのファイルを使ってbuild.gradleを作成する仕組みになっています。
([こちらの方の記事](https://qiita.com/tkyaji/items/0c9857e40e5876af1770)によるとUnity5.5.2からできるようになったらしいです。私はUnity5.6.6で実際にできることを確認しました)

### mainTemplate.gradleにPlayServicesプラグインの依存関係を記入する

カスタムのmainTemplate.gradleを用意したら後はここにPlayServicesプラグインの依存関係を記述していきます。

必要な記述は2カ所です。

まず、プラグインを入手するためのリポジトリを記載します。
リポジトリとはプラグインをネットワーク経由などから入手する際の置き場所です。
mainTemplate.gradleの下記の記載がリポジトリの指定箇所です。

```gradle
// 修正前
allprojects {
   repositories {
      flatDir {
        dirs 'libs'
      }
   }
}
```

PlayServicesプラグインの場合は「`https://maven.google.com`」辺りにあるようなのでそちらの設定を記入します。
(詳しい書き方はGradleを勉強してね！)

```gradle
// 修正後
allprojects {
   repositories {
      flatDir {
        dirs 'libs'
      }
      maven {
        url "https://maven.google.com"
      }
   }
}
```

次にPlayServicesプラグインの依存関係を記載します。
mainTemplate.gradleの記載は下記です。

```gradle
// 修正前
dependencies {
	compile fileTree(dir: 'libs', include: ['*.jar'])
**DEPS**}
```

PlayServicesResolverでは〜Dependencies.csや〜Dependencies.xmlなどResolver独自のクラスや記法で依存ファイルを作っていると思いますがGradleの記載は簡単です。
例えば下記のように記載します。

```gradle
// 修正後
dependencies {
	compile fileTree(dir: 'libs', include: ['*.jar'])
	compile 'com.google.android.gms:play-services-ads:11.8.0'
	compile 'com.android.support:recyclerview-v7:27.0.2'
	compile 'com.android.support:cardview-v7:27.0.2'
	compile 'com.android.support.constraint:constraint-layout:1.0.2'
	compile 'com.android.support:support-v4:27.0.2'
**DEPS**}
```

より具体的な情報が公式にまとめられているようなので詳しく知りたい方はこちらもご覧になると良いでしょう。(英語)
https://developers.google.com/android/guides/setup

これで準備は完了です。
後はビルドを行うとGradleツールが依存関係に記載されたプラグインを確認して無ければ取得してきてくれます。
(もちろんUnityプロジェクトにPlayServicesResolverを導入する必要もありません)

おまけ：Gradleプロジェクトを出力してビルドする手順例
----

BuildSettingsで「Build System」をGradleに設定し、さらにUnityからGradleビルドを行うか、Gradleプロジェクトをエクスポートして自分でGradleビルドを行うかを選ぶことができます。

エクスポートする場合は「Build System」の下にある「Export Project」にチェックを入れてください。
チェックを入れると「Build」ボタンが「Export」ボタンに変化します。

<img width="621" alt="image_build_export_project.png" src="https://qiita-image-store.s3.amazonaws.com/0/30406/13272b98-b7b7-c579-9b9e-d2f28abd1031.png">

「Export」ボタンを押すと指定したディレクトリにGradleプロジェクトを出力してくれます。

このGradleプロジェクトはAndroidStudioで開くこともできるそうですが、例えばPlayServicesプラグインを初回に組み込むときに、上手く行くまで繰り返しUnityから出力させて試行するには手間がかかるかもしれません。
(出力時に上書きすれば気にならない？)

私の場合はAndroidStudioを使わずにコマンドラインから直接Gradleビルドを実行してビルド時のトラブル調査や試行を繰り返しました。

コマンドラインからGradleビルドを実行する場合は予め必要なバージョンのGradleツールをインストールして使えるようにしておくか、「Gradle Wrapper」などを作成して利用してください。

下記では(私の方で実際に行った手順ということで)Gradleツールで「Gradle Wrapper」(gradlew)を作成し、gradlew経由でGradleビルドを実行する手順を例に挙げます。

エクスポートしたGradleプロジェクトに必要なGradleツールバージョンはmainTemplate.gradleの最初の方に記載されています。
出力するUnityエディタのバージョンで必要なGradleツールバージョンも異なるようです。

```gradle
dependencies {
	classpath 'com.android.tools.build:gradle:2.3.0'
}
```

コマンドライン上からカレントをGradleプロジェクトのルートディレクトリへ移動し、下記のコマンドを実行してください。(予めGradleのインストールが必要)

```bash
$ gradle wrapper
```

実行するとカレントディレクトリに「gradlew」という実行形式のファイルが作成されます。
これを使って下記のように実行するとGradleビルドが実行されます。
(パスが通ってないのでカレントディレクトリからの相対パスで指定してます)

```bash
$ ./gradlew build
```

これでGradleビルドが実行され、上手くいくとカレントディレクトリにbuildディレクトリが作成されその中に作成物ができます。(apkファイルとか)

上手く行かないとエラーが表示され、失敗するので原因を解消してからUnityのエクスポートやGradleビルドを繰り返します。

ビルドに成功するようになったら、UnityのBuildSettingsにある「Export Project」のチェックを外して以降はUnityからGradleビルドを回すようにすると良いかと思います。

おまけその２：PlayServicesResolverだと困ったこと詳細
----

### UnityのAndroidManifest.xmlのマージツールが厳格過ぎる

- 「A.aar」と「B.aar」に異なる属性値が入ってるよ〜と延々ビルドを通せない。
- 自前の設定なら調整で何とかできることもあるが、サードパーティ製のプラグインが原因だとどうにもならないことがあったりする。
    - 私の場合、FOXとAdStirとFirebaseなどを同時に入れないとみたいな案件があって地獄でした。。。
    - aarをzip解凍して自前でいじったりもできますができる限りやりたくない。。。
    - Gradleビルドだとこの辺りがもう少し柔軟みたい。(必ず大丈夫とは限りませんが)

### パッケージ名(バンドルID)の自動置換をResolver実行時にしか行ってくれない

- Resolver独自の機能(？)なのか、aar内のAndroidManifest.xmlの中に記載されている「${applicationId}」をパッケージ名に置き換えてくれる機能がある。
- が、この置き換えはResolverがUnityエディタにPlayServicesプラグインをDLして組み込むときにのみ行う。
    - PlayerSettingsに記載されているバンドルIDを使っているようです。

私の関わったプロジェクトでは下記の要件が必要でした。

- DeployGateの配信先などを切り替える
    - 開発用アプリとステージング用アプリとか。
    - バンドルIDを別のものに変えると同時に両方をインストールできて便利。
- サードパーティ製のプラグインサービスのアカウントをパブリッシャーと切り替える
    - サービスにバンドルIDを紐付ける必要がある

これを実現させるため、エディタ拡張スクリプトでビルド時にバンドルIDを切り替える運用にしていたため、Resolverの置き換えてくれる機能では不十分でした。
(Androidビルドが通らない、動かない、でここで心が折れた)

まとめ
----

PlayServicesResolverに苦戦してからのGradleビルドへの移行を試してみたお話でした。
正直、私はもうGradleビルドだけ使ってUnityのPlayServicesResolverのことは忘れたら良いのではと思いました。

AndroidStudioやGradle自体の知識に詳しいわけでは無いので今回の手順の中には実はさらに簡単にできるよみたいな手順があるかもしれないです。
(間違いが含まれている場合はごめんなさい。気づいたときにできるだけ直すようには気をつけます)

また、Gradle自体はとても強力なツールのようでmainTemplate.gradleをさらにカスタマイズすると色んな便利なことができるかもしれませんね。
(Gradleの知識やAndroidの知識が色々と必要そうですが。。。その内勉強してみよう)

そちらは詳しい方にお任せするということで、
今回は表題のことについて参考程度にご覧いただけたら幸いです。