Azure PipelinesのYAMLでXamarin.Forms製アプリのストア配布パイプラインを構築する方法

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

第1部: [CI環境の構築](https://qiita.com/uhooi/items/f830165143eb7dd9d8bd)
第2部: [App Center配布パイプラインの構築](https://qiita.com/uhooi/items/a4bb5282eed708dadb40)
第3部: ストア配布パイプラインの構築　__←イマココ__

## はじめに

本記事は [エムティーアイ Advent Calendar 2021](https://qiita.com/advent-calendar/2021/mti) の3日目の記事です。
昨日は @piz032 さんで [自分の考える保守開発スケジューリングの心得](https://qiita.com/piz032/items/374cd0c9d432ccb1e94b) でした。

Azure Pipelinesを使い、Xamarin.Forms製アプリをストアへ配布するCDを構築します。

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

- Azure Pipelinesの概要や基本的な操作方法  
[私が以前書いた記事](https://qiita.com/uhooi/items/5ed8db6aaec01425e453) が参考になると思います
- [CI環境の構築](https://qiita.com/uhooi/items/f830165143eb7dd9d8bd) と [AppCenter配布パイプラインの構築](https://qiita.com/uhooi/items/a4bb5282eed708dadb40) で説明した内容  
以前説明した内容を説明するのは冗長なのでしません

## パスワードの追加

[AppCenter配布パイプラインの構築](https://qiita.com/uhooi/items/a4bb5282eed708dadb40) で説明していない内容のみ紹介します。

### iOS: App Store Connectのユーザー名とパスワードの追加

[Azure PipelinesのYAMLでiOSアプリのTestFlight配布パイプラインを構築する方法](https://qiita.com/uhooi/items/f421fcd02a6594653924#app-store-connectのユーザー名とパスワードの追加) と同様なので詳細は省略します。

変数は以下の通りです。

|Variable|説明|機密|
|:--|:--|:--|
|`AscUserName`|App Store Connectのユーザー名|×|
|`AscPassword`|App Store Connectのパスワード|○|

## 設定ファイルの作成

今回は以下の環境でストアに配布します。

- `production`
  - iOS・Android共にリリースビルド

配布先がApp Centerからストアに変わる以外は、基本的に `develop` や `staging` と同様です。

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

trigger: none

jobs:
- job: distribute_testflight_ios
  pool:
    vmImage: 'macOS-11'
  variables:
  - group: Foo-iOS-Signing-Distribution
  - name: XamarinSymlinkVersion
    value: '6_12_8'
  - name: XcodeVersion
    value: '13.0'
  - name: DEVELOPER_DIR
    value: '/Applications/Xcode_$(XcodeVersion).app'
  steps:
  # iOSアプリをTestFlightへ配布
  - template: templates/distribute-testflight-ios-template.yml

- job: distribute_playconsole_android
  pool:
    vmImage: 'macOS-11'
  variables:
  - group: Foo-Android-Signing-Release
  - name: XamarinSymlinkVersion
    value: '6_12_8'
  - name: BuildConfiguration
    value: 'release'
  steps:
  # AndroidアプリをGoogle Play Consoleへ配布
  - template: templates/distribute-playconsole-android-template.yml
```

次にテンプレートを作成します。
Androidは配布とAABファイルの生成方法が未調査なので、APKファイルの生成までしか行っていません。

```yaml:templates/distribute-testflight-ios-template.yml
steps:
# 証明書のインストール
- task: InstallAppleCertificate@2
  inputs:
    certSecureFile: 'foo_distribution.p12'
    certPwd: '$(P12Password)'

# Provisioning Profileのインストール
- task: InstallAppleProvisioningProfile@1
  inputs:
    provProfileSecureFile: 'foo_appstore.mobileprovision'

# iOS固有のセットアップ
- template: setup/setup-ios-template.yml

# Xamarinのセットアップ
- template: setup/setup-xamarin-template.yml

# IPAファイルの生成
- task: XamariniOS@2
  displayName: 'Build an iOS app with Xamarin on macOS'
  inputs:
    solutionFile: '**/*.sln'
    configuration: 'AppStore'
    clean: true
    signingIdentity: 'Apple Distribution'
    signingProvisioningProfileID: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'

# アーティファクトのステージングへコピー
- task: CopyFiles@2
  displayName: 'Copy IPA to Build.ArtifactStagingDirectory'
  inputs:
    Contents: '**/*.ipa'
    TargetFolder: '$(Build.ArtifactStagingDirectory)'

# アーティファクトへアップロード
- task: PublishBuildArtifacts@1
  inputs:
    ArtifactName: 'store_ios'

# IPAファイルのバリデーション
- script: xcrun altool --validate-app -f **/*.ipa -t ios -u $(AscUserName) -p $(AscPassword)
  displayName: Validate IPA

# TestFlightへ配布
- script: xcrun altool --upload-app -f **/*.ipa -t ios -u $(AscUserName) -p $(AscPassword)
  displayName: Distribute IPA to TestFlight
```

```yaml:templates/distribute-playconsole-android-template.yml
steps:
# Xamarinのセットアップ
- template: setup/setup-xamarin-template.yml

# APKファイルの生成
- task: XamarinAndroid@1
  displayName: 'Build an Android app with Xamarin'
  inputs:
    projectFile: '**/*.Android.csproj' 
    outputDirectory: '$(Build.BinariesDirectory)/$(BuildConfiguration)'
    configuration: '$(BuildConfiguration)'

# APKファイルの署名
- task: AndroidSigning@3
  displayName: 'Sign and align Android APK files'
  inputs:
    apkFiles: '$(Build.BinariesDirectory)/$(BuildConfiguration)/*.apk'
    apksignerKeystoreFile: 'foo_release.keystore'
    apksignerKeystorePassword: '$(KeystorePassword)'
    apksignerKeystoreAlias: '$(KeyAlias)'
    apksignerKeyPassword: '$(KeyPassword)'

# アーティファクトのステージングへコピー
- task: CopyFiles@2
  displayName: 'Copy APK to Build.ArtifactStagingDirectory'
  inputs:
    Contents: '$(Build.BinariesDirectory)/$(BuildConfiguration)/*.apk'
    TargetFolder: '$(Build.ArtifactStagingDirectory)'

# アーティファクトへアップロード
- task: PublishBuildArtifacts@1
  inputs:
    ArtifactName: '$(BuildConfiguration)_android'

# TODO: Google Play Consoleへ配布
```

## おわりに

Azure PipelinesのYAMLでXamarin.Forms製アプリをストアへ配布することができました！

これでXamarin.Forme製アプリのCI/CD環境が整いました。
どんなアプリにも適用できるので、ぜひCI/CD環境構築の参考にしてください。

以上 [エムティーアイ Advent Calendar 2021](https://qiita.com/advent-calendar/2021/mti) の3日目の記事でした。
明日も @uhooi の記事です。