「Azure PipelinesのYAMLでXamarin.Forms製アプリのCI/CD環境を構築する」は3部構成です。
記事を順番に読み進めると、Azure PipelinesでXamarin.Forms製アプリのCI/CD環境が構築できるようになります。
第1部: CI環境の構築
第2部: App Center配布パイプラインの構築 ←イマココ
第3部: ストア配布パイプラインの構築
はじめに
本記事は Azure DevOps Advent Calendar 2021 の2日目の記事です。
昨日は @kkamegawa さんで Azure DevOps ServiceでTLS 1.0/1.1が無効化されます でした。
Azure Pipelinesを使い、Xamarin.Forms製アプリをApp Centerへ配布するCDを構築します。
本記事で説明しないこと
- Azure Pipelinesの概要や基本的な操作方法
私が以前書いた記事 が参考になると思います - Visual Studio App Centerの概要や基本的な操作方法
-
CI環境の構築 で説明した内容
以前説明した内容を説明するのは冗長なのでしません
App Centerのコネクションを追加
Azure PipelinesのYAMLでiOSアプリのApp Center配布パイプラインを構築する方法 と同様なので省略します。
証明書のアップロード
アプリの署名に必要なファイルをアップロードします。
iOS: 証明書とProvisioning Profileのアップロード
Azure PipelinesのYAMLでiOSアプリのApp Center配布パイプラインを構築する方法 と同様なので省略します。
Android: キーストアのアップロード
Azure PipelinesのYAMLでAndroidアプリのApp Center配布パイプラインを構築する方法 と同様なので省略します。
証明書のパスワードの追加
iOS: P12ファイルのパスワードの追加
追加方法は Azure PipelinesのYAMLでiOSアプリのApp Center配布パイプラインを構築する方法 と同様なので詳細は省略します。
{アプリ名}-iOS-Signing-{証明書の種類}
でVariable groupを複数作成し、中身の変数名を統一することで、変数を簡単に切り替えられるのでオススメです。
例として以下のVariable groupを作成します。
Foo-iOS-Signing-Development
Foo-iOS-Signing-Distribution
変数は以下の通りです。
Variable | 説明 | 機密 |
---|---|---|
P12Password |
P12ファイルのパスワード | ○ |
Android: キーストアと鍵のパスワードの追加
追加方法は Azure PipelinesのYAMLでAndroidアプリのApp Center配布パイプラインを構築する方法 と同様なので詳細は省略します。
iOSと同様、Variable groupを複数作成します。
Foo-Android-Signing-Debug
Foo-Android-Signing-Release
変数は以下の通りです。
Variable | 説明 | 機密 |
---|---|---|
StorePassword |
キーストアのパスワード | ○ |
KeyAlias |
キーストアのエイリアス | × |
KeyPassword |
キーストアの鍵のパスワード | ○ |
設定ファイルの作成
今回は以下2つの環境でApp Centerに配布します。
-
develop
- iOS・Android共にデバッグビルド
-
staging
- iOS・Android共にリリースビルド
まずは全環境の設定ファイルを作成します。
見てわかる通りVariable groupとテンプレートのみ変えています。
ライブラリなどのバージョンを管理しやすくするため、まとめて変数として定義しています。
name: $(SourceBranchName)_$(Date:yyyyMMdd)$(Rev:.r)
trigger: none
jobs:
- job: distribute_appcenter_ios
pool:
vmImage: 'macOS-11'
variables:
- group: Foo-iOS-Signing-Development
- name: XamarinSymlinkVersion
value: '6_12_8'
- name: XcodeVersion
value: '13.0'
- name: DEVELOPER_DIR
value: '/Applications/Xcode_$(XcodeVersion).app'
steps:
# iOSアプリをApp Centerへ配布
- template: templates/distribute-appcenter-debug-ios-template.yml
- job: distribute_appcenter_android
pool:
vmImage: 'macOS-11'
variables:
- group: Foo-Android-Signing-Debug
- name: XamarinSymlinkVersion
value: '6_12_8'
- name: BuildConfiguration
value: 'Debug'
steps:
# AndroidアプリをApp Centerへ配布
- template: templates/distribute-appcenter-debug-android-template.yml
name: $(SourceBranchName)_$(Date:yyyyMMdd)$(Rev:.r)
trigger: none
jobs:
- job: distribute_appcenter_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アプリをApp Centerへ配布
- template: templates/distribute-appcenter-adhoc-ios-template.yml
- job: distribute_appcenter_android
pool:
vmImage: 'macOS-11'
variables:
- group: Foo-Android-Signing-Release
- name: XamarinSymlinkVersion
value: '6_12_8'
- name: BuildConfiguration
value: 'release'
steps:
# AndroidアプリをApp Centerへ配布
- template: templates/distribute-appcenter-release-android-template.yml
次にテンプレートを作成します。
steps:
# 証明書のインストール
- task: InstallAppleCertificate@2
inputs:
certSecureFile: 'foo_development.p12'
certPwd: '$(P12Password)'
# Provisioning Profileのインストール
- task: InstallAppleProvisioningProfile@1
inputs:
provProfileSecureFile: 'foo_debug.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: 'debug'
clean: true
signingIdentity: 'Apple Development'
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: 'debug_ios'
# App Centerへ配布
- task: AppCenterDistribute@3
inputs:
serverEndpoint: 'App Center'
appSlug: '{Organization}/{App}'
appFile: '**/*.ipa'
releaseNotesOption: 'input'
releaseNotesInput: |
- Configuration: Debug
- Certificate: $(APPLE_CERTIFICATE_SIGNING_IDENTITY)
- Provisioning Profile: $(APPLE_PROV_PROFILE_UUID)
- 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'
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_debug.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'
# App Centerへ配布
- task: AppCenterDistribute@3
inputs:
serverEndpoint: 'App Center'
appSlug: '{Organization}/{App}'
appFile: '**/$(BuildConfiguration)/*.apk'
releaseNotesOption: 'input'
releaseNotesInput: |
- Build Configuration: $(BuildConfiguration)
- Keystore: foo_debug.keystore
- 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'
steps:
# 証明書のインストール
- task: InstallAppleCertificate@2
inputs:
certSecureFile: 'foo_distribution.p12'
certPwd: '$(P12Password)'
# Provisioning Profileのインストール
- task: InstallAppleProvisioningProfile@1
inputs:
provProfileSecureFile: 'foo_adhoc.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: 'Ad-Hoc'
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: 'adhoc_ios'
# App Centerへ配布
- task: AppCenterDistribute@3
inputs:
serverEndpoint: 'App Center'
appSlug: '{Organization}/{App}'
appFile: '**/*.ipa'
releaseNotesOption: 'input'
releaseNotesInput: |
- Configuration: Ad-Hoc
- Certificate: $(APPLE_CERTIFICATE_SIGNING_IDENTITY)
- Provisioning Profile: $(APPLE_PROV_PROFILE_UUID)
- 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'
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'
# App Centerへ配布
- task: AppCenterDistribute@3
inputs:
serverEndpoint: 'App Center'
appSlug: '{Organization}/{App}'
appFile: '**/$(BuildConfiguration)/*.apk'
releaseNotesOption: 'input'
releaseNotesInput: |
- Build Configuration: $(BuildConfiguration)
- Keystore: foo_release.keystore
- 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'
iOS固有とXamarinのセットアップのテンプレートも作成します。
XcodeやXamarin SDKのバージョンは、以下のページを参考に指定しています。
Xamarin.iOSやXamarin.AndroidはXamarin.Monoとバージョンを揃えるべきだと思うので、macOSエージェントに用意されている symlink
を使って指定するのが望ましいです。
symlink
のバージョンがどのXamarin SDKに紐付いているかは、macOSエージェントのREADMEに記載されています。
steps:
# Xcodeの選択
- script: |
echo '##vso[task.setvariable variable=MD_APPLE_SDK_ROOT;]'$(DEVELOPER_DIR);sudo xcode-select --switch $(DEVELOPER_DIR)/Contents/Developer
xcodebuild -version
displayName: 'Select Xcode $(XcodeVersion)'
steps:
# Xamarin SDKの選択
- script: |
sudo $AGENT_HOMEDIRECTORY/scripts/select-xamarin-sdk.sh $(XamarinSymlinkVersion)
ls -l /Library/Frameworks/Mono.framework/Versions/
ls -l /Library/Frameworks/Xamarin.iOS.framework/Versions/
ls -l /Library/Frameworks/Xamarin.Android.framework/Versions/
mono --version
msbuild -version
displayName: 'Select Xamarin SDK $(XamarinSymlinkVersion)'
# NuGetパッケージの復元
- task: NuGetCommand@2
displayName: 'NuGet restore'
inputs:
command: 'restore'
restoreSolution: '**/*.sln'
他は基本的に以下と同様なので省略します。
- Azure PipelinesのYAMLでiOSアプリのApp Center配布パイプラインを構築する方法
- Azure PipelinesのYAMLでAndroidアプリのApp Center配布パイプラインを構築する方法
おわりに
Azure PipelinesのYAMLでXamarin.Forms製アプリをApp Centerへ配布することができました!
以上 Azure DevOps Advent Calendar 2021 の2日目の記事でした。
明日は @zt_megane さんで「Azure DevOpsでスクラムプロジェクトを始める時に設定していること」です。
参考リンク
- Build Xamarin apps - Azure Pipelines | Microsoft Docs
- Install Apple Certificate task - Azure Pipelines | Microsoft Docs
- Install Apple Provisioning Profile task - Azure Pipelines | Microsoft Docs
- Xamarin.iOS build and release task - Azure Pipelines | Microsoft Docs
- Xamarin.Android build and release task - Azure Pipelines | Microsoft Docs
- Android signing build and release task - Azure Pipelines | Microsoft Docs
- NuGet restore, pack, and publish task - Azure Pipelines | Microsoft Docs