XcodeGen で Flutter の .xcodeproj 管理を手軽にする
はじめに 🎉
XcodeGen を用いて ios/Runner.xcodeproj
を生成する Flutter のサンプルリポジトリを作成しました!
dev
, prd
の 2 つの Flavor ごとに以下の出しわけを想定した project.yml
を作成しています。
- アプリアイコン
- アプリの表示名
- Bundle ID
- Firebase Project
project.pbxproj
のつらみ 😢
Flutter で iOS アプリを開発していると、時折 Xcode 開いて編集する機会があると思います。
Xcode の GUI で編集した後に ios/Runner.xcodeproj/project.pbxproj
の diff を見てみると👇のように非常にわかりにくい差分が生まれていることがあります。
https://github.com/react-native-community/cli/issues/652 より
iOS 開発では複数人が Xcode を操作することでこのファイルのコンフリクトに悩むことが多々ある[1][2]ようで、この問題を解決するツールの一つに XcodeGen があります。
XcodeGen とは 💻
XcodeGen は以下のような project.yml
などの yml ファイルから、Xcode の設定である .xcodeproj
を自動生成してくれるツールです。Flutter では flutter create
で生成される ios/Runner.xcodeproj
というファイル群がこれに該当します。
name: Runner
options:
xcodeVersion: '15.4.0'
developmentLanguage: ja
deploymentTarget:
iOS: 16.0
include:
- xcodegen/setting/base.yml
configs:
Debug: Debug
Debug-dev: Debug-dev
Debug-prd: Debug-prd
Profile: Profile
Profile-dev: Profile-dev
Profile-prd: Profile-prd
Release: Release
Release-dev: Release-dev
Release-prd: Release-prd
...
XcodeGen の詳しい使い方や説明はわかりやすい記事が多数ありますのでそちらを参照ください。
- https://qiita.com/uhooi/items/16a870eaae24b46103fb
- https://zenn.dev/entaku/articles/6bcae21711a89c
- https://buildersbox.corp-sansan.com/entry/2020/12/24/110000
SPM(Swift Package Manager) との比較 👀
同様の問題の解決策として 2024 年 6 月現在、 iOS 界隈では XcodeGen よりも SPM を使う流れが加速しているようです[3][4][5][6]。Flutter でもこちらの PR で SPM の対応が merge されています。
しかし Flutter v3.22.0 の段階では使用できないこと、パッケージ側の対応がされていない場合は CocoaPods との併用が必要になるため今回は採用しませんでした。
Flutter 開発に XcodeGen を活用する 🤖
Flutter 開発では project.pbxproj
がコンフリクトすることはあまりありませんが、前述したように差分が非常にわかりにくく、PR のレビューなどに苦戦する問題があります。
XcodeGen の解説記事や情報のほとんどは、iOS のネイティブ開発用であるため今回 Flutter で XcodeGen を活用するサンプルのリポジトリを作成しました 🚀
このリポジトリでは dev
, prd
の 2 つの Flavor に対応した Flutter アプリの .xcodeproj
を生成する project.yml
を作成しています。
よくある Flutter のユースケースを想定し、Flavor ごとに以下の要素を分けるようになっています。
- アプリアイコン
- アプリの表示名
- Bundle ID
- Firebase Project
使い方は簡単で .tool-versions
に定義されている各種ツールを用意(本リポジトリでは asdf を使用しています) した後、以下のコマンドで .xcodeproj
を作成、アプリを実行するだけです。
cd ios && xcodegen generate
flutter run --flavor dev(or prd)
XcodeGen 用のファイル群 📁
XcodeGen に関わるファイル群の構成は以下のようになっています。
ios
├── project.yml
└── xcodegen
├── script
│ ├── check_pods_manifest.sh
│ ├── copy_pods_resources.sh
│ ├── crashlytics_upload_symbols.sh
│ ├── embed_pods_frameworks.sh
│ ├── run_script.sh
│ ├── select_google_service_info_plist.sh
│ └── thin_binary.sh
└── setting
├── base.yml
├── debug-dev.yml
├── debug-prd.yml
├── debug.yml
├── profile-dev.yml
├── profile-prd.yml
├── profile.yml
├── release-dev.yml
├── release-prd.yml
└── release.yml
ios/xcodegen/script/
には、 Xcode 上の Build Phases タブで定義されているスクリプトをそれぞれ切り出しています。
Xcode 上の Build Phases タブ
ios/xcodegen/setting/
には、 configs ごとの Build Settings タブの内容を記述しています。base.yml
で各 config ごとの値の include と共通設定の記述を担っています。
メインとなる project.yml の全体像は以下の通りです。各項目の詳細な説明については公式のドキュメントを参照してください。
Firebase Project を Flavor ごとに分ける場合 🔥
Firebase のプロジェクトをセットアップした後、各 Flavor ごとに使用したいGoogleService-Info.plist
を ios/GoogleService/{Flavor}
配下に配置します。
さらに build 時に ios/
に Flavor ごとの GoogleService-Info.plist
をコピーするスクリプトを実行する必要があります[3:1]。このための設定はコメントアウトされているので、必要に応じてコメントアウトを解除して利用してください。
Firebase Crashlytics を使用する場合 💥
コンソール上のログを見やすくするために postBuildPhase で dSYM のアップロードをする必要があります。こちらもコメントアウトされているので、必要に応じてコメントアウトを解除して利用してください。
さいごに 🎬
XcodeGen は最初のキャッチアップが大変なので、その一助になれば幸いです!
@_cokaholic さんに色々教わりながら作成しました!大感謝です!
Discussion