🛠️

[Flutter] Xcode Cloudを使って配布を自動化したときのメモ

2024/10/03に公開

自分が何ヶ月後かに同じ作業をすることになった場合のためのメモです。

Xcode Cloudを設定する

  • 接続をXcodeから行う必要がある
  • Integrate > Create Wolkflow...
  • 接続するアプリを選択し、GitHubとも接続する。そのため、当然だけどAppStoreConnectにアプリを作っておく必要がある。
  • 1回Xcodeから接続が完了すれば、あとは基本的にAppStoreConnectの該当アプリページにあるXcode Cloudからワークフローの編集が可能。

Custom Build Scriptsの作成

  • flutterアプリのため、ビルド前に実行させたい処理も多いためCustom Build Scirptsを設定します。
  • iosフォルダ以下にci_scriptsフォルダを作成し、その下にシェルスクリプトを配置します。ios/ci_scripts/*
  • Writing custom build scripts
  • 以下の3種類のファイルを認識します。
    • ci_post_clone.sh
      • Xcode Cloud が Git リポジトリをクローンした後に実行される。
      • 追加のツールをインストールしたり、プロパティにエントリを追加したり。
    • ci_pre_xcodebuild.sh
      • Xcode Cloud がxcodebuildを実行する前に実行される
      • 追加の依存関係をコンパイルしたり。
    • ci_post_xcodebuild.sh
      • Xcode Cloud がxcodebuildを実行した後に実行される。
      • 成果物をストレージや他のサービスにアップロードする処理などに使う

ci_post_clone.sh

  • まだfvmのバージョンが2系だからfvm_config参照してるけど参考サイトに貼ってる記事の方なら.fvmrc使われてるのでそっち参考にしたほうがいいかもね。
  • flutter buildをflavorで環境切り分けてるので、Xcode CloudのWolkflowから環境変数としてbuildFlavorを追加して共通の記述から処理が分岐するようにしています。
ci_post_clone.sh
#!/bin/sh

# Fail this script if any subcommand fails.
set -e

# The default execution directory of this script is the ci_scripts directory.
cd $CI_PRIMARY_REPOSITORY_PATH # change working directory to the root of your cloned repo.

# Extract the Flutter version from fvm_config file
FLUTTER_VERSION=$(cat .fvm/fvm_config.json | grep "flutterSdkVersion" | cut -d '"' -f 4)

# Clone the Flutter repository with the specified version
git clone https://github.com/flutter/flutter.git --depth 1 -b $FLUTTER_VERSION $HOME/flutter
export PATH="$PATH:$HOME/flutter/bin"

# Print the Flutter version
flutter --version

# Install Flutter artifacts for iOS (--ios), or macOS (--macos) platforms.
flutter precache --ios

# Install Flutter dependencies.
flutter pub get

# Install CocoaPods using Homebrew.
HOMEBREW_NO_AUTO_UPDATE=1 # disable homebrew's automatic updates.
brew install cocoapods

# Install CocoaPods dependencies.
cd ios && pod install # run `pod install` in the `ios` directory.

# The flutterfire command is used in Xcode Build Phases and must be installed in advance.
dart pub global activate flutterfire_cli
export PATH="$PATH":"$HOME/.pub-cache/bin"

flutter build ios --config-only --flavor ${buildFlavor} --dart-define=FLAVOR="${buildFlavor}"

exit 0

ci_post_xcodebuild.sh

  • xcodebuildの完了後にipaをFirebase Distributionにアップロードします。
  • 現状、Xcode Cloudにはビルドしてアーカイブするワークフローしかないので場合分けをしていないが、test実行などを追加する場合は$CI_WORKFLOWなどを利用してif分岐すること
  • Environment variable reference
ci_post_xcodebuild.sh
brew install firebase-cli
firebase appdistribution:distribute "$CI_AD_HOC_SIGNED_APP_PATH/${ipaName}.ipa" --app "${firebaseAppId}" --token "${FIREBASE_TOKEN}" --groups "${firebaseGroup}"

クリーンビルド

  • TestFlightで配布する場合は必須でチェックが入る

環境変数の追加

  • firebaseAppId
    • Firebaseの管理画面から設定にあるAppleアプリを選択
    • アプリ ID欄にあるIDを指定
  • firebaseGroup
    • Firebase Distributionで配布するテスターグループを指定する。
    • テスターとグループ欄から配布先に指定したいグループを選択すると、「テスターを検索」欄の右上あたりにヘルプマークでコマンドライン ツールでグループを指定する際に、このエイリアスを使用します。と設定されてる文字列があると思うのでそれをコピー。
  • FIREBASE_TOKEN
    • 以下で取得できるtokenを指定。
    • そのうちGCPのサービスアカウントに変更が必要かも・・・。
firebase login:ci
  • ipaName
    • アプリ名として自分が指定している名前でipaが作られるはず。
    • よくわからなければ、1回Xcode Cloudを実行したあとで成果物に登録されるipaをダウンロードして確認

開始条件

  • デフォルトだと全てのブランチがpushされるたびに実行される設定になっているため、必ず変更する
  • 現在の環境では以下を設定している。dev版の場合はproductionではなくdevelopment
    • ブランチの変更としてupload-production/で始まるブランチが変更された場合
    • タグの変更としてproductionで始まるタグ

アクション

  • アーカイブ - iOS
    • 本番の場合は本番向けのスキームを指定
    • 配信準備は「App Store Connect」にするとTestFlight向けの準備もされる。
    • dev版でTestFlightへの配信も必要ない場合は「なし」で大丈夫。

ポストアクション

  • TestFlight内部テスト - iOS
    • アクションの配信準備でTestFlightまたはAppStoreConnectを選択していないと実行できない
    • これを指定しないと、自動的にTestFlightビルドは配布されない。
  • 通知する - 成功と失敗
    • Slack通知を設定しておくと便利

その他

pubspec.yaml
dependency_overrides:
  url_launcher_ios: 6.3.1
  • カスタムビルドスクリプトにchmod +x &ci_post_clone.shなどの形で実行権限を付与する

参考

Discussion