Flutter Flavorsの設定をXcode GUI操作なしで自動化するプラグイン作ってみた
はじめに
Flutter Flavorsの環境分け、Android側はファイル編集だけで完結しますが、iOS側はXcodeのGUI操作が必須です。Build Configurationの複製、Scheme作成、紐付け... flavor数だけ繰り返すのは面倒でミスも起きやすい。
本記事では、Xcode GUI操作なしでFlavor設定を完全自動化する方法を紹介します。なぜ --flavor のみで環境分けするのかについてはこちらの記事で整理しています。
本記事の内容はClaude Codeプラグインとして公開しています。スキルを実行するだけで、Flutterプロジェクトの初期化からflavor設定まで完了します。
伝えたいこと
flutter createが生成するproject.pbxprojのUUIDは毎回同じ値になる- この性質を利用すれば、iOS側のFlavor設定をテンプレート適用だけで自動化できる
前提
iOS側のFlavor設定が面倒な理由
公式ドキュメントに従うと、以下のXcode GUI操作が必要です。
| 操作 | 方法 |
|---|---|
| Build Configuration複製 | Project > Info > Configurations |
| Scheme作成 | Product > Scheme > New Scheme |
| Scheme-Config紐付け | Manage Schemes > Edit |
| Bundle ID設定 | Build Settings > Packaging |
| User-Defined Setting追加 | Build Settings > + |
Android側は build.gradle.kts にproductFlavorsを追加するだけで完結するのに対し、iOS側はこれらをflavor数分だけ手動で繰り返す必要があります。
自動化のアプローチ
発想: 差分をテンプレート化する
Xcode GUIの操作結果は全てファイル(project.pbxproj、*.xcscheme)に記録されます。一度手動で設定して git diff を取れば、テンプレート化できるはずです。
壁: project.pbxproj のUUID問題
project.pbxproj の各エントリにはUUIDが割り振られています。
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = { ... };
name = Debug;
};
Build Configurationを追加するとXcodeがランダムに新しいUUIDを生成するため、プロジェクトAで取った差分をプロジェクトBにそのまま適用できません。
突破口: flutter create のUUIDは固定
flutter create はテンプレートからプロジェクトを生成するため、既存のUUIDは毎回同じ値になります。
flutter create project_a --org com.example
flutter create project_b --org com.test
diff <(grep -E "^ [0-9A-F]{24}" project_a/ios/Runner.xcodeproj/project.pbxproj) \
<(grep -E "^ [0-9A-F]{24}" project_b/ios/Runner.xcodeproj/project.pbxproj)
差分ゼロ。つまり flutter create 直後に適用する前提なら、UUID問題は発生しません。新規に追加するエントリのUUIDもテンプレートにハードコードしておけばOKです。
テンプレート設計と適用手順
ファイル構成
flavor/
├── android/
│ └── build.gradle.kts.snippet
├── ios/
│ ├── pbxproj-configurations-dev.txt # dev用
│ ├── pbxproj-configurations-stg.txt # stg用
│ ├── pbxproj-configurations-prod.txt # prod用
│ ├── pbxproj-instructions.md # UUID対応表
│ └── scheme.xcscheme.template # {{FLAVOR}} 置換で各環境分生成
└── dart/
├── env.dart.template
└── launch.json.template
pbxprojの設定はflavorごとにファイルを分割し、dev,prod のみ・dev,stg,prod 全部など柔軟に選択できるようにしています。
適用手順
Android: build.gradle.kts にproductFlavorsを挿入、AndroidManifest.xml の android:label を @string/app_name に変更。
iOS — project.pbxproj:
- XCBuildConfiguration挿入 — 指定flavorの設定ブロックを
/* End XCBuildConfiguration section */の直前に挿入。{{BUNDLE_ID}}・{{APP_DISPLAY_NAME}}をプロジェクトの値に置換 - 既存設定の修正 — Runner ターゲットの Debug / Release / Profile に
APP_DISPLAY_NAME = "";を追加(UUIDはflutter create固定) - XCConfigurationList更新 — Project / Runner / RunnerTests の3つのリストに、追加flavorのエントリを挿入
iOS — その他: Schemeテンプレートから各flavorのSchemeを生成・配置、Info.plist の CFBundleDisplayName を $(APP_DISPLAY_NAME) に変更。
Dart / VS Code: lib/core/env.dart にFlavor enum、.vscode/launch.json に起動設定を配置。
DEVELOPMENT_TEAM(Apple Developer Team ID)は開発者ごとに異なるため、テンプレートには含めず初回ビルド時のXcode自動設定に任せます。
動作確認
flutter build apk --flavor dev --debug
# ✓ Built build/app/outputs/flutter-apk/app-dev-debug.apk
flutter build ios --flavor dev --debug --no-codesign
flutter build ios --flavor stg --debug --no-codesign
flutter build ios --flavor prod --debug --no-codesign
# ✓ 全flavorでビルド成功
注意点
Flutter SDKのバージョンアップ
テンプレートは flutter create の固定UUIDに依存しています。メジャーバージョンアップ時はUUIDの確認が必要です。
flutter create uuid_check --org com.test
grep -E "^ [0-9A-F]{24}" uuid_check/ios/Runner.xcodeproj/project.pbxproj
CocoaPods導入時
ネイティブプラグイン追加で Podfile が生成された際、全Configurationの列挙が必要です。
project 'Runner', {
'Debug' => :debug,
'Debug-dev' => :debug,
'Debug-prod' => :debug,
'Release' => :release,
'Release-dev' => :release,
'Release-prod' => :release,
'Profile' => :release,
'Profile-dev' => :release,
'Profile-prod' => :release,
}
まとめ
| 項目 | 手動 | 自動化後 |
|---|---|---|
| Android flavor設定 | ファイル編集 | テンプレート適用 |
| iOS Build Configuration | Xcode GUI | テンプレート挿入 |
| iOS Scheme | Xcode GUI | テンプレート生成 |
| iOS Info.plist | Xcode GUI | ファイル編集 |
| Dart環境分岐 | 手書き | テンプレート配置 |
flutter create のUUIDが固定であるという性質を利用することで、Xcode GUIを一切触らずにFlavor設定を完全自動化できました。テンプレートのメンテナンスコスト(Flutter SDKアップデート時のUUID確認)はありますが、頻度を考えれば十分にペイする仕組みだと思います。







