Unity の Android 版自動ビルド環境を構築する (Self-hosted 環境)

#はじめに

[クラウドで Unity 自動ビルド環境の構築](https://qiita.com/akiojin/items/149705a090f60211a4dd) では Win64 でビルドを行ったのですが、Android 版の場合は署名が必要になります。

今回は Android のビルド＆コード署名までを行いたいと思います。

#ゴール

- Unity の Self-hosted 環境で Android ビルドと APK の署名

#事前準備

以下の記事で事前準備をしておいてください。

- [証明書などの保存方法](https://qiita.com/akiojin/items/054e73e5b65fea950757)

#ソースコード

まずはソースコードです。

```yml
trigger:
- master

variables:
  Unity.TargetBuild: 'Android'
  Unity.ProjectPath: '$(Build.SourcesDirectory)'
  
  Keystore.FileName: '<Keystore FileName>'
  Keystore.Alias: '<Alias Name>'

  Output.FileName: 'drop'

pool:
  name: 'Unity Agent for Mac'

jobs:
  - job: Unity
    displayName: 'Unity Android build started.'
    condition: or(not(variables['Unity.UserName']), not(variables['Unity.Password']), not(variables['Unity.SerialKey']))
    workspace:
      clean: outputs

    steps:
    - task: UnityGetProjectVersionTask@1
      name: UnityGetProjectVersion
      displayName: 'Getting a version of Unity'
      inputs:
        unityProjectPath: '$(Unity.ProjectPath)'

    - bash: echo "##vso[task.setvariable variable=ANDROID_ROOT]/Applications/Unity/Hub/Editor/$(UnityGetProjectVersion.projectVersion)/PlaybackEngines/AndroidPlayer"
      displayName: 'Set ANDROID_ROOT'
    - bash: echo "##vso[task.setvariable variable=ANDROID_HOME]$(ANDROID_ROOT)/SDK"
      displayName: 'Set ANDROID_HOME'
    - bash: echo "##vso[task.setvariable variable=JAVA_HOME]$(ANDROID_ROOT)/OpenJDK"
      displayName: 'Set JAVA_HOME'

    - task: UnityBuildTask@3
      displayName: 'Unity Building.'
      condition: succeeded()
      inputs:
        buildTarget: '$(Unity.TargetBuild)'
        unityProjectPath: '$(Unity.ProjectPath)'
        outputPath: '$(Build.BinariesDirectory)'
        outputFileName: '$(Output.FileName)'

    - task: AndroidSigning@3
      displayName: 'Signing the APK File.'
      inputs:
        apkFiles: '$(Build.BinariesDirectory)/*.apk'
        apksignerKeystoreFile: '$(Keystore.FileName)'
        apksignerKeystorePassword: '$(Keystore.Password)'
        apksignerKeystoreAlias: '$(Keystore.Alias)'
        apksignerKeyPassword: '$(Keystore.Password)'
        zipalign: true

    - task: CopyFiles@2
      displayName: 'Copying builds...'
      condition: succeeded()
      inputs:
        SourceFolder: '$(Build.BinariesDirectory)'
        Contents: '*.apk'
        TargetFolder: '$(Build.ArtifactStagingDirectory)'
        CleanTargetFolder: true
        OverWrite: true

    - task: PublishBuildArtifacts@1
      displayName: 'Publish builds...'
      condition: succeeded()
      inputs:
        PathtoPublish: '$(Build.ArtifactStagingDirectory)'
        ArtifactName: 'Release'
        publishLocation: 'Container'
```

#ANDROID_HOME の設定

Android 版の自動ビルドで一番躓いた箇所は ANDROID_HOME の設定でした。
Self-hosted の場合、環境変数に ANDROID_HOME を指定する方法はあまり得策ではない、と言うか Unity のインストールで『Android SDK & NDK Tools』『OpenJDK』が、バージョンごとにインストールされるパスが違いますので、それを Unity のプロジェクトバージョンを元に参照するパスを切り替えということをしたほうが良いという結論になりました。

```yml
- bash: echo "##vso[task.setvariable variable=ANDROID_ROOT]/Applications/Unity/Hub/Editor/$(UnityGetProjectVersion.projectVersion)/PlaybackEngines/AndroidPlayer"
  displayName: 'Set ANDROID_ROOT'
- bash: echo "##vso[task.setvariable variable=ANDROID_HOME]$(ANDROID_ROOT)/SDK"
  displayName: 'Set ANDROID_HOME'
- bash: echo "##vso[task.setvariable variable=JAVA_HOME]$(ANDROID_ROOT)/OpenJDK"
  displayName: 'Set JAVA_HOME'
```

Pipelines では

```yml
- bash: echo "##vso[task.setvariable variable=<変数名>]変数に設定する値"
```

で変数を設定可能です。
また variables で変数を宣言しておかなくても変数が利用可能です。

#APK ファイルの署名

Android の署名に必要な

- Keystore ファイル
- Keystore パスワード
- Keystore エイリアス

を YAML で利用します。

```yml
variables:
  Keystore.FileName: '<Keystore FileName>'
  KeyStore.Alias: '<Alias Name>'
#  KeyStore.Password: 事前に Variables に設定しておく

- task: AndroidSigning@3
  displayName: 'Signing the APK File.'
  inputs:
    apkFiles: '$(Build.BinariesDirectory)/*.apk'
    apksignerKeystoreFile: '$(Keystore.FileName)'
    apksignerKeystorePassword: '$(Keystore.Password)'
    apksignerKeystoreAlias: '$(Keystore.Alias)'
    apksignerKeyPassword: '$(Keystore.Password)'
    zipalign: true
```

[証明書などの保存方法](https://qiita.com/akiojin/items/054e73e5b65fea950757) で保存されているセキュアファイルライブラリから Keystore ファイルを参照するだけで、署名付きの APK ファイルが作成されます。

※最近では Gradle を利用したビルド環境を作ることも多いですが、今回は Gradle は利用せずに Unity で生成された APK をそのまま利用しています。

#おわりに

署名自体はそんなに難しくないです。
Pipelines のセキュアファイルライブラリが便利ですので、それが出来れば Android ビルドも怖くないです。