Azure PipelinesのYAMLでAndroidアプリのApp Center配布パイプラインを構築する方法

「Azure PipelinesのYAMLでAndroidアプリのCI/CD環境を構築する」は3部構成です。
記事を順番に読み進めると、Azure PipelinesでAndroidアプリのCI/CD環境が構築できるようになります。

- 第一部：[CI環境の構築](https://qiita.com/uhooi/items/2c81ce98907eb29fef7d)
- 第二部：App Center配布パイプラインの構築　__←イマココ__
- 第三部：Google Play Console配布パイプラインの構築（未投稿）

## はじめに

Azure Pipelinesを使い、AndroidアプリをApp Centerへ配布するCDを構築します。

## 本記事で説明しないこと

- Azure Pipelinesの概要や基本的な操作方法  
[私が以前書いた記事](https://qiita.com/uhooi/items/5ed8db6aaec01425e453)が参考になると思います
- Visual Studio App Centerの概要や基本的な操作方法
- [CI環境の構築](https://qiita.com/uhooi/items/2c81ce98907eb29fef7d)で説明した内容  
以前説明した内容を説明するのは冗長なのでしません

## App Centerのコネクションを追加

[Azure PipelinesのYAMLでiOSアプリのApp Center配布パイプラインを構築する方法](https://qiita.com/uhooi/items/1245344a6add3e86cdc8#app-centerのコネクションを追加) と同様なので省略します。

## キーストアのアップロード

必要に応じてキーストアをSecure fileへアップロードします。
アップロードの方法は [こちら](https://qiita.com/uhooi/items/1245344a6add3e86cdc8#%E8%A8%BC%E6%98%8E%E6%9B%B8%E3%81%A8provisioning-profile%E3%81%AE%E3%82%A2%E3%83%83%E3%83%97%E3%83%AD%E3%83%BC%E3%83%89) をご参照ください。

私はApp Center用のキーストアはリポジトリに直接コミットしており、Secure fileは使っていません。

## キーストアと鍵のパスワードの追加

必要に応じてキーストアと鍵のパスワードをVariablesに追加します。
追加方法は [こちら](https://qiita.com/uhooi/items/1245344a6add3e86cdc8#p12%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E3%83%91%E3%82%B9%E3%83%AF%E3%83%BC%E3%83%89%E3%81%AE%E8%BF%BD%E5%8A%A0) をご参照ください。

私はApp Center用のキーストアと鍵のパスワードは `/app/build.gradle` に直接書いています。

## 設定ファイルの作成

今回はビルドタイプを `debug` に固定し、プロダクトフレーバーを以下の3つすべてでApp Centerに配布できるようにします。

- `develop`
- `staging`
- `production`

プロダクトフレーバーが異なる以外は同じ処理なので、Azure DevOpsのテンプレートを利用し、共通処理を別のYAMLファイルに抜き出します。

まずは全プロダクトフレーバーの設定ファイルを作成します。
見てわかる通り `productFlavor` に渡す値のみ変えています。

```yaml:distribute-appcenter-develop-debug.yml
name: $(SourceBranchName)_$(Date:yyyyMMdd)$(Rev:.r)

trigger: none

jobs:
- job: distribute_appcenter_develop_debug
  pool:
    vmImage: 'ubuntu-latest'

  steps:
  # App Centerへ配布
  - template: templates/distribute-appcenter-debug-template.yml
    parameters:
      productFlavor: 'develop'
```

```yaml:distribute-appcenter-staging-debug.yml
name: $(SourceBranchName)_$(Date:yyyyMMdd)$(Rev:.r)

trigger: none

jobs:
- job: distribute_appcenter_staging_debug
  pool:
    vmImage: 'ubuntu-latest'

  steps:
  # App Centerへ配布
  - template: templates/distribute-appcenter-debug-template.yml
    parameters:
      productFlavor: 'staging'
```

```yaml:distribute-appcenter-production-debug.yml
name: $(SourceBranchName)_$(Date:yyyyMMdd)$(Rev:.r)

trigger: none

jobs:
- job: distribute_appcenter_production_debug
  pool:
    vmImage: 'ubuntu-latest'

  steps:
  # App Centerへ配布
  - template: templates/distribute-appcenter-debug-template.yml
    parameters:
      productFlavor: 'production'
```

次にテンプレートを作成します。

```yaml:templates/distribute-appcenter-debug-template.yml
parameters:
- name: productFlavor
  type: string

steps:
# JDKのセットアップ
- task: JavaToolInstaller@0
  inputs:
    versionSpec: '11'
    jdkArchitectureOption: 'x64'
    jdkSourceOption: 'PreInstalled'

# 依存関係の出力
- script: ./gradlew androidDependencies
  displayName: Displays the Android dependencies of the project

# APKの生成
- script: ./gradlew assembleDebug
  displayName: Generate APK for debug

# アーティファクトのステージングへコピー
- task: CopyFiles@2
  inputs:
    Contents: |
      **/app/build/outputs/apk/${{ parameters.productFlavor }}/debug/app-${{ parameters.productFlavor }}-debug.apk
    TargetFolder: '$(Build.ArtifactStagingDirectory)'

# アーティファクトへアップロード
- task: PublishBuildArtifacts@1
  inputs:
    pathtoPublish: '$(Build.ArtifactStagingDirectory)'
    artifactName: 'drop'
    publishLocation: 'Container'

# App Centerへ配布
- task: AppCenterDistribute@3
  inputs:
    serverEndpoint: 'App Center'
    appSlug: '{Organization}/{App}'
    appFile: '**/app/build/outputs/apk/${{ parameters.productFlavor }}/debug/app-${{ parameters.productFlavor }}-debug.apk'
    releaseNotesOption: 'input'
    releaseNotesInput: |
      - Product Flavor: ${{ parameters.productFlavor }}
      - Build Type: debug
      - Keystore: {Keystore name}
      - Build ID: $(Build.BuildId)
      - Build Number: $(Build.BuildNumber)
      - Reason: $(Build.Reason)
      - Requested For: $(Build.RequestedFor)
      - Source Branch: $(Build.SourceBranch)
      - Last Commit ID: $(Build.SourceVersion)
      - Last Commit Comment: $(Build.SourceVersionMessage)
      - Release Note: $(ReleaseNote)
    destinationType: 'groups'
```

App CenterはAAB形式に対応していないため、APK形式でアップロードします。
参考: https://github.com/microsoft/appcenter/issues/955

AAB形式でアップロードしようとすると、以下のエラーが出力されます。

```
##[error]{"code":"not_supported","message":"Error: Distribution of .aab is not supported for groups/testers"}
```

他は基本的に [Azure PipelinesのYAMLでiOSアプリのApp Center配布パイプラインを構築する方法](https://qiita.com/uhooi/items/1245344a6add3e86cdc8#%E5%90%84%E9%A0%85%E7%9B%AE%E3%81%AE%E7%B4%B9%E4%BB%8B) と同様なので省略します。

## おわりに

Azure PipelinesのYAMLでAndroidアプリをApp Centerへ配布することができました！

テンプレートを利用することで共通処理をまとめられ、設定ファイルがスッキリしました。

## 参考リンク

### APK

- [コマンドラインからアプリをビルドする  |  Android デベロッパー  |  Android Developers](https://developer.android.com/studio/build/building-cmdline?hl=ja)

### Templates - Azure Pipelines

- [Templates - Azure Pipelines | Microsoft Docs](https://docs.microsoft.com/en-us/azure/devops/pipelines/process/templates?view=azure-devops)
- [(114) Azure Multistage Pipelines Part3 - YouTube](https://www.youtube.com/watch?v=d2FevFzDzPY)
- https://twitter.com/kkamegawa/status/1362985070114447364

### App Center

- [App Center Distribute task - Azure Pipelines | Microsoft Docs](https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/deploy/app-center-distribute?view=azure-devops)
- https://twitter.com/the_uhooi/status/1367403673580494851?s=20