noxi雑記

.NET、Angularまわりの小ネタブログ

Xamarin iOSアプリをAzure PipelinesでビルドしてAppCenterに送信する(ビルド編)

Azure Pipelines 使っていますか? 昨今は GitHub Actions に後塵を拝している感が否めませんが、マルチステージを利用した承認機能など、実は結構便利に利用できます。今回は Xamarin.Forms で実装した iOS アプリをビルドするための Azure Pipelines を組んでみます。またビルド結果を AppCenter へ送信し、テスト配布も行います。

全体を一本の記事にするととても長くなってしまうためビルドとテスト配布の2つに分割しました。本記事は前編のビルド編です。



環境

今回試したものはこちらに置いてあります。

github.com

ビルドYAML全体

Xamarin iOS をビルドする Pipeline YAML は全体でこのようになります。

variables:
  BuildConfiguration: 'Ad-Hoc'
  DotnetSdkVersion: '3.1.404'
  MonoVersion: '6_12_0'
  XcodeRootPath: '/Applications/Xcode_12.2.app'

#  - AppleCertificatePassword: 'dummy' これはPipelineの環境変数にSecure属性で登録する

pool:
  vmImage: 'macOS-10.15' # or 'macOS-latest'

steps:

  # .NET SDK をインストール
  - task: UseDotNet@2
    inputs:
      packageType: 'sdk'
      version: '$(DotnetSdkVersion)'

  # mono バージョンを固定
  - script: sudo $AGENT_HOMEDIRECTORY/scripts/select-xamarin-sdk.sh $(MonoVersion)

  # Xcode バージョンを固定
  - script: echo '##vso[task.setvariable variable=MD_APPLE_SDK_ROOT;]'$(XcodeRootPath);sudo xcode-select --switch $(XcodeRootPath)/Contents/Developer

  # Provisioning Profile をインストール
  # 'sample.mobileprovision' を SecureFiles に保存しておく
  - task: InstallAppleProvisioningProfile@1
    inputs:
      provisioningProfileLocation: secureFiles
      provProfileSecureFile: 'sample.mobileprovision'
      removeProfile: true

  # 署名証明書をインストール
  # 'sample.p12' を SecureFiles に保存しておく
  # AppleCertificatePassword を Secure 設定で環境変数に設定しておく
  - task: InstallAppleCertificate@2
    inputs:
      keychain: 'temp'
      certSecureFile: 'sample.p12'
      certPwd: '$(AppleCertificatePassword)'

  # NuGet tools をインストール
  - task: NuGetToolInstaller@1

  # NuGet パッケージを復元
  - task: NuGetCommand@2
    inputs:
      command: 'restore'
      restoreSolution: '**/*.csproj'
      feedsToUse: 'select'

  # Xamarin iOS アプリをビルド
  - task: XamariniOS@2
    inputs:
      solutionFile: 'SampleApp.sln'
      configuration: '$(BuildConfiguration)'
      packageApp: true
      runNugetRestore: false
      args: '/p:IpaPackageDir="$(Build.ArtifactStagingDirectory)"'
      signingIdentity: '$(APPLE_CERTIFICATE_SIGNING_IDENTITY)'
      signingProvisioningProfileID: '$(APPLE_PROV_PROFILE_UUID)'

  # ビルド結果の ipa ファイルを Pipeline Artifacts へ転送
  - task: PublishBuildArtifacts@1
    condition: succeededOrFailed()
    inputs:
      PathtoPublish: '$(Build.ArtifactStagingDirectory)'

Azure Pipeline Tasks

ここからは Xamarin iOS のビルドに使用する Azure Pipelines のタスクを紹介します。

InstallAppleProvisioningProfile@1

Azure Pipelines でビルドに使用するマシンに Provisioning Profile をインストールするタスクです。インストールする Provisioning Profile は Secure Filesに保存したものから選択します。インストールされた Provisioning Profile をステージ完了時に削除するオプションもあり安心です。またこのタスクを利用してインストールした Provisioning Profile は APPLE_PROV_PROFILE_UUID 変数に ID が格納されます。

docs.microsoft.com

task: InstallAppleProvisioningProfile@1
inputs:
  provisioningProfileLocation: 'secureFiles'
  provProfileSecureFile: 'sample.mobileprovision'
  removeProfile: true

Secure Files を使用する

Secure Files は Azure Pipelines の Library 機能の一つです。 Provisioning Profile やビルド用の証明書など、 Repository に含めたくないファイルを管理できます。

f:id:noxi515:20201206164426p:plain
Secure Filesの場所

アップロードしたファイルは Authorize for use in all piplines にチェックを入れることで全ての Pipeline から参照可能になります。

f:id:noxi515:20201206165537p:plain
全ての Pipeline から利用する為のチェック

InstallAppleCertificate@2

Azure Pipelines でビルドに使用するマシンに Apple の署名証明書をインストールするタスクです。インストールする証明書は Secure Filesに保存したものから選択します。デフォルトでインストールされた証明書はステージ完了時に削除されるためこちらも安心です。またこのタスクを使用してインストールした証明書は APPLE_CERTIFICATE_SIGNING_IDENTITY に格納されます。

docs.microsoft.com

task: InstallAppleCertificate@2
inputs:
  keychain: 'temp'
  certSecureFile: 'sample.p12'
  certPwd: '$(AppleCertificatePassword)'

XamariniOS@2

Xamarin iOS アプリをビルドするためのタスクです。前述の InstallAppleProvisioningProfile タスクと InstallAppleCertificate タスクを実行して得られた結果を利用すると配布用の実機ビルドを実行できます。ビルド時の引数で IpaPackageDir を指定するとビルド結果の *.ipa ファイルを拾いやすいです。
runNugetRestore を設定するとビルド時に NuGet の復元をしてくれるため便利ですが、事前にテストタスクを回すことが多いと思いますので、別途 NuGet Restore タスクを実行することをお勧めします。
solutionFile にはビルド対象の sln または csproj を指定します。ここは必ずソリューションファイルを指定しましょう。 Xamarin iOS をではビルドの設定が iPhoneAd-Hoc など多々存在し、依存プロジェクト側は DEBUGRELEASE のみの場合があります。ソリューションファイルにはこのビルド情報が格納されていますので、直接 Xamarin iOS のプロジェクトファイルのみをビルドすると依存プロジェクトがビルドできません。

docs.microsoft.com

task: XamariniOS@2
inputs:
  solutionFile: 'SampleApp.sln'
  configuration: '$(BuildConfiguration)'
  packageApp: true
  runNugetRestore: false
  args: '/p:IpaPackageDir="$(Build.ArtifactStagingDirectory)"'
  signingIdentity: '$(APPLE_CERTIFICATE_SIGNING_IDENTITY)'
  signingProvisioningProfileID: '$(APPLE_PROV_PROFILE_UUID)'

ビルドに利用するバージョンを固定する

ビルドに使用する macOS マシンは Azure Pipelines 側が管理しているものを使用すると、 Xcode などのバージョンは日々更新されていきます。ビルドに使用するものはバージョンが新しければ良いというものではなく、「何もしていないのにビルドが壊れた」という自体になりかねません。そこで、ビルドに使用するバージョンを固定する方法を紹介します。
なお Azure Pipelines で使用できる macOS マシンにインストールされているツールやバージョンはこちらから確認します。

docs.microsoft.com

github.com

mono のバージョンを固定する

ビルドタスクに以下を挟みます。環境変数として MonoVersion=6_12_0 と、 mono バージョンのドットをアンダースコアに変換したmonoを指定します。

script: sudo $AGENT_HOMEDIRECTORY/scripts/select-xamarin-sdk.sh $(MonoVersion)

どの mono バージョンを指定すれば良いのかは私にも良く分かりません。。。

Xcode のバージョンを固定する

ビルドタスクに以下を挟みます。環境変数として XcodeRootPath=/Applications/Xcode_12.2.app を指定します。指定可能な Xcode パスの一覧は前述のビルドマシン環境情報を参照して下さい。

script: echo '##vso[task.setvariable variable=MD_APPLE_SDK_ROOT;]'$(XcodeRootPath);sudo xcode-select --switch $(XcodeRootPath)/Contents/Developer