Flutter iOS 起動画面とアプリアイコン
Flutterアプリ向けに実戦で検証されたパターン:最初のフレームでネイティブ起動ロゴを表示し、iOSのCustomize→Default/Dark/Clear/Tintedに対応したホーム画面アイコンを提供します。
使用するタイミング
- コールドスタート時にFlutterが読み込まれる前に白/アイボリーの画面が表示される場合
- システムの外観(アプリ内のThemeCubitではない)に従うLight + Dark起動ロゴが必要な場合
- iOS 18+でアプリアイコンのDark/Tinted/Clearバリアントが必要な場合
使用しないタイミング
- Androidのスプラッシュ画面やFlutterアプリ内のSplashScreenのみを扱う場合
- アプリ内テーマトグル(HydratedBloc)を変更する場合 — これは起動画面やSpringBoardアイコンには影響しません
重要なルール(必ず守ること)
- 起動ロゴはアプリバンドル内の個別PNGファイルとして配置し、アセットカタログのイメージセットとしては使いません。SplashBoardがAssets.carから
UIImage imageNamedで画像を読み込もうとすると最初のスナップショットで失敗し、2~3秒間空白のキャンバスになることがよくあります。 - Assets.xcassetsにBrandLogoを配置しないでください。同じベース名のファイルが個別に存在する場合、カタログが優先されて読み込みに失敗します。
- LaunchScreenの背景色はストーリーボードで明示的なsRGB値を指定します。名前付きカラー(例:
LaunchBackground)は起動スナップショットで切り替わらないことがよくあります。 - Trait Variationのキーは
userInterfaceStyle=darkです(interfaceStyleやluminosity=darkではありません)。 - ビルド済みの.appに
ibtoolで作成したstoryboardcを複製して起動を確認しないでください。黒いフラッシュが発生します。常にflutter build ios --simulator(または実機)でビルドし、アンインストール+再インストールを行ってください。 - Dark/Tintedを追加した後に
flutter_launcher_iconsを実行しないでください。Contents.jsonを上書きして外観設定を削除します。 - ホーム画面アイコンはiPhoneの外観設定/Customizeに従い、Flutterテーマには従いません。ClearはTintedから自動派生し、別途Clear用のスロットはありません。
ワークフローチェックリスト
進捗:
- [ ] 1. Light + Night起動PNGを生成(@1x/@2x/@3x)
- [ ] 2. ios/Runner/にコピーし、Copy Bundle Resourcesに追加(pbxproj)
- [ ] 3. Assets.xcassetsからBrandLogo*.imagesetを削除
- [ ] 4. LaunchScreen.storyboardを更新(個別画像名+明示的な色)
- [ ] 5. オプション:Main.storyboard/SceneDelegateの引き継ぎ用にLaunchBackground.colorset
- [ ] 6. アプリアイコンのDark + Tinted 1024px画像を生成(レガシーエントリを残す場合はホームサイズも)
- [ ] 7. AppIcon.appiconset/Contents.jsonにluminosity dark + tintedを追加
- [ ] 8. flutter build ios --simulator --debug
- [ ] 9. simctl uninstall + install; 起動が0.5秒未満、Assets.car内のアイコン外観を確認
ステップ1 — 起動ロゴの生成
scripts/generate_launch_logos.py を使用します。
入力:
- ダークなスタジオ背景のソースロゴ(典型的には
assets/logo/logo.png) - Light版:黒を抜き、2トーンのブランドカラーを維持
- Dark版:同じアルファマスクで、ソリッドゴールド
#E0B45D(またはプロジェクトのプライマリカラー) - サイズ:400×363 @1x、800×727 @2x、1200×1090 @3x(ロゴのアスペクト比に合わせて調整)
抜き処理の計算式(FlutterのSplashLogoが存在する場合はそれに合わせます):
alpha_out = min(255, 4 * (R + G + B), source_alpha)
出力ファイルを ios/Runner/ に配置:
BrandLogo.png、[email protected]、[email protected]BrandLogoNight.png、[email protected]、[email protected]
ステップ2 — バンドルリソース
ios/Runner.xcodeproj/project.pbxproj 内:
- 6つのPNGすべてに
PBXFileReference+PBXBuildFileを追加 - RunnerグループおよびCopy Bundle Resourcesにリスト
lastKnownFileType = image.png;@2x/@3xのパスは引用符で囲む
ios/Runner/Assets.xcassets/BrandLogo.imageset と BrandLogoNight.imageset が存在する場合は削除します。
ビルド後、確認:
# BrandLogoはAssets.carにあってはならない;PNGはRunner.appに存在する
find build/ios/iphonesimulator/Runner.app -name 'BrandLogo*.png'
xcrun assetutil --info build/ios/iphonesimulator/Runner.app/Assets.car | grep -i BrandLogo || true
ステップ3 — LaunchScreen.storyboard
最新のIB形式を使用(toolsVersion ≥ 21701、useTraitCollections、機能「documents saved in the Xcode 8 format」)。
パターン(完全テンプレート:references/launch-storyboard.md):
UIImageViewcontentMode="scaleAspectFit"、画像BrandLogo- バリエーション:
key="userInterfaceStyle=dark" image="BrandLogoNight" - 幅はスーパービューの約0.28~0.40(最初は0.32程度);高さ = 幅 × ロゴのアスペクト比
- 中央X/Yの制約
- Light背景:明示的なsRGB(例:アイボリー
#FFFCF7) - Dark背景バリエーション:明示的なsRGB(例:
#17120E) <resources>内で両方の画像名を内包サイズとともに宣言する必要あり
Info.plist: UILaunchStoryboardName = LaunchScreen。
ステップ4 — Flutterへの引き継ぎ(推奨、必須ではない)
Flutterが引き継ぐときの白いフラッシュを防ぐ:
LaunchBackground.colorsetをLight + Darkの明度で作成(起動以外のUIでは問題ありません)- Main.storyboardのVC背景 →
LaunchBackgroundという名前 - SceneDelegate / カスタム
FlutterViewController:viewDidLoad/viewDidLayoutSubviewsでview.backgroundColorとwindow.backgroundColorをUIColor(named: "LaunchBackground")で設定
ステップ5 — アプリアイコンの外観(iOS 18+)
scripts/generate_app_icon_variants.py を使用して、1024マーケティングアイコン(クリーム背景+ロゴ)から生成します。
| 外観 | アートワーク |
|---|---|
| デフォルト(Any) | 既存のLightアイコン |
| Dark | ダークプレート(#17120E)上のゴールドロゴ、またはApple HIGに従い透明背景 |
| Tinted | グレースケール:黒背景上の白/灰色ロゴ(システムがティントを適用) |
| Clear | Tintedから自動派生 — Contents.jsonにエントリ不要 |
AppIcon.appiconset/Contents.json を更新 — 詳細は references/appicon-contents.md を参照。
ユニバーサル1024エントリはSingle Sizeを推奨:
"appearances": [{ "appearance": "luminosity", "value": "dark" }]
"appearances": [{ "appearance": "luminosity", "value": "tinted" }]
プロジェクトでまだ使用している場合は、レガシーなサイズ別iPhoneエントリも維持する;最低でも60pt @2x/@3x + マーケティング1024に対してDark/Tintedを追加する。
検証:
xcrun actool ios/Runner/Assets.xcassets --compile /tmp/icons \
--platform iphonesimulator --minimum-deployment-target 15.0 \
--app-icon AppIcon --output-partial-info-plist /tmp/icon-partial.plist
xcrun assetutil --info /tmp/icons/Assets.car | grep -E 'UIAppearanceDark|ISAppearanceTintable'
ビルドされたアプリは、UIAppearanceDark と ISAppearanceTintable が設定された AppIcon をリストするはずです。
ステップ6 — シミュレータで確認
flutter build ios --simulator --debug
xcrun simctl uninstall booted <bundle.id>
xcrun simctl install booted build/ios/iphonesimulator/Runner.app
# 起動:約0.4~0.5秒でロゴが表示されることを期待(数秒の空白ではない)
# アイコン:Customize → Dark / Tinted;SpringBoardのキャッシュにより、削除+再インストールが必要な場合あり
サンドボックスなエージェント環境では、simctlにフル権限が必要です。
SplashBoardキャッシュを rm -rf で削除しないでください;アンインストール+再インストールで起動スナップショットはクリアされます。
ブランドのデフォルト値(プロジェクトごとに上書き可能)
| トークン | デフォルト |
|---|---|
| Light起動背景 | #FFFCF7 |
| Dark起動背景 | #17120E |
| Darkロゴゴールド | #E0B45D |
| 起動ロゴ幅 | 画面の32% |
| Darkアイコンプレート | #17120E |
プロジェクトが異なる場合は、ユーザーにブランドの16進色の値を尋ねてください。
追加リソース
- ストーリーボードXMLテンプレート:references/launch-storyboard.md
- アプリアイコンContents.jsonの形状:references/appicon-contents.md
- 起動ロゴ生成スクリプト:scripts/generate_launch_logos.py
- アイコンバリアント生成スクリプト:scripts/generate_app_icon_variants.py