4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Azure DevOpsAdvent Calendar 2021

Day 2

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

Last updated at Posted at 2021-12-02

「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とテンプレートのみ変えています。

ライブラリなどのバージョンを管理しやすくするため、まとめて変数として定義しています。

distribute-appcenter-develop.yml
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
distribute-appcenter-staging.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

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

templates/distribute-appcenter-debug-ios-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'
templates/distribute-appcenter-debug-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_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'
templates/distribute-appcenter-adhoc-ios-template.yml
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'
templates/distribute-appcenter-release-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'

# 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に記載されています。

templates/setup/setup-ios-template.yml
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)'
templases/setup/setup-xamarin-template.yml
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でXamarin.Forms製アプリをApp Centerへ配布することができました!

以上 Azure DevOps Advent Calendar 2021 の2日目の記事でした。
明日は @zt_megane さんで「Azure DevOpsでスクラムプロジェクトを始める時に設定していること」です。

参考リンク

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?