【Flutter】初期設定が不要になるテンプレートを作りたい

アプリ開発、やりたいけどめんどくさい問題
こんなアプリ欲しいぃぃぃぃ!このアイデアよくね???
という思いは束の間。10s laterには他のこと考えています。これが界隈との差か...
僕はだらしないので、めんどくささ、やる気、気分が味方になってくれずなかなか手がつきません。
今回はこの3つの要因のうち「めんどくささ」にフォーカスしたソリューションになります。
やる気、気分は解決しないのでそこは自分でどうにかしてください。僕も頑張ります。
この記事で私は発信デビューです。温かい目で見てもらえたら幸いでございます。
そんなこんなで今回は面倒な作業を全てテンプレート化しようと思います。
最初からアプリ開発に集中できる環境を整えましょうってことですね!
例えば以下のような作業。flavorに関わる内容が多いっす
- fvm
- DBアクセス設定
- スプラッシュ
- アプリアイコン
- アプリ名
- モデルのテンプレート
- Firebaseの基本的な部分(authなど)
- フッター
- router
- android, iOS両方のビルド可能な状態

まずはvscodeのコマンドパレットからflutter new project
プロジェクト名は「flutter_app_template」にしました。
一旦この時点でgitにpushしとこう。

さて、まずはfvmの設定ですね。
fvm releases
でflutterのバージョン一覧を見てみましょう。
最新は3.27.3みたいです。とりあえず最新を使います。
fvm use 3.27.3
gitコミットしときましょうね

ではこの段階でiOSビルドして問題ないか確認しておきます。
launch.jsonがないとvscodeのGUIからデバッグできません。
create a launch.json file
すればおkです
ビルドしたらプロテインを飲みながら待ちましょう。
iOSビルドできましたね。
androidも見とくかあ。
ヤニ吸ってる間に済ませましょう。
なんて言ってる間に終わって草。ありがとう。
iOS,androidともに問題ないですね。
fvm設定しただけなのでビルドできて当然ですが、ちょくちょくチェックポイント作っておくのは個人的に大事だと思います。
もしこれ以降にビルドできない問題が発生しても「ここまでは問題なかった」と切り分けできるので、今回に限らず普段から意識しておくのはいいことだと思われまする。

Flavor設定やってくぞ(dart define from file)
方針
「dart define from file」でflavorを設定します。
Flavor① 「from file」のfileを作成します。
今回は開発環境(dev)と本番環境(prod)としてFlavorを設定しようと思います。
以下のように環境ごとに設定値を定義するファイルを作成しました。
ディレクトリ構成は後々整理するとして
- lib/flavor/dev.json
- lib/flavor/prod.json
に配置しています。
{
"FLAVOR": "dev",
"APP_NAME": "開発環境",
"APP_ID": "com.nuggetdyson.template.dev"
}
{
"FLAVOR": "prod",
"APP_NAME": "本番環境",
"APP_ID": "com.nuggetdyson.template"
}
今は一旦飛ばしますが、DBアクセスの設定値なども環境ごとにこのファイルに記述していきます。
Flavor② iOS ①の変数をXcodeに流せるようにする
flutter 3.19 から標準でdart define from fileが利用できなくなりました。
そのためにこちらの作業が必要となってきます。
- スクリプトファイルを作成
- XcodeのBuild Pre-actionsに1のスクリプトを実行するように設定
以下のファイルを作成します。
#!/bin/sh
# 参考:https://zenn.dev/altiveinc/articles/separating-environments-in-flutter#ios%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AB%E5%BF%85%E8%A6%81%E3%81%AA%E5%AF%BE%E5%BF%9C
# Dart defineを書き出すファイルパスを指定します。
# ここでは `Dart-Defines.xcconfig` というファイル名で作成することにします。
OUTPUT_FILE="${SRCROOT}/Flutter/Dart-Defines.xcconfig"
# Dart defineの中身を変更した時に古いプロパティが残らないように、初めにファイルを空にしています。
: > $OUTPUT_FILE
# この関数でDart defineをデコードします。
function decode_url() { echo "${*}" | base64 --decode; }
IFS=',' read -r -a define_items <<<"$DART_DEFINES"
for index in "${!define_items[@]}"
do
item=$(decode_url "${define_items[$index]}")
# Dartの定義にはFlutter側で自動定義された項目も含まれます。
# しかし、それらの定義を書き出してしまうとエラーによりビルドができなくなるので、
# flutterやFLUTTERで始まる項目は出力しないようにしています。
lowercase_item=$(echo "$item" | tr '[:upper:]' '[:lower:]')
if [[ $lowercase_item != flutter* ]]; then
echo "$item" >> "$OUTPUT_FILE"
fi
done
次にXcodeでのbuild pre actionの設定ですね
画面上部のメニューからProduct>Scheme>Edit Scheme
から設定します。
「+」ボタンで新しくスクリプトを登録できます。
Provide build settings from: Runner
`${SRCROOT}/scripts/extract_dart_defines.sh`
参考記事m(._.)m
iOSビルドを行って確認してみましょう。
その前にlaunch.json
からflaverの情報を流すような設定が必要です。
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "dev",
"request": "launch",
"type": "dart",
+ "args": [
+ "--dart-define-from-file=lib/flavor/dev.json",
+ ],
},
{
"name": "prod",
"request": "launch",
"type": "dart",
+ "args": [
+ "--dart-define-from-file=lib/flavor/prod.json",
+ ],
},
]
}
これでビルドしてみましょう!
ios/Flutter/Dart-Defines.xcconfig
が生成されています。
中身をのぞいてみると、jsonで設定した変数が定義されているのがわかりますね。(devでビルドしてます)
自動で動的に生成されるファイルなのでgitignoreも忘れずにしておきましょう
+ # Flavor defines
+ Flutter/Dart-Defines.xcconfig
次はこれらの値をXcode上で参照してアプリ名やbundle idを動的に設定できるようにしていきます。

Flavor③ iOS ①の変数を参照し設定する(Xcode)
どこで設定するねん>ios/Runner/Info.plist
Xcodeで表示してみましょう
ふむふむ。どうやら$(FLUTTER_BUILD_NAME)
のように動的な設定値は$(XXX)
で指定してやればええんすね。
既存のこやつらはどこに元にあるんや?
$(PRODUCT_BUNDLE_IDENTIFIER)
→ targets>Runner>Build Setting
$(FLUTTER_BUILD_NAME)
$(FLUTTER_BUILD_NUMBER)
→ios/Flutter/Generated.xcconfig
$(EXECUTABLE_NAME)
$EXECUTABLE_PREFIX
$PRODUCT_NAME
$EXECUTABLE_SUFFIX
の連結らしいです。よくわからないのでそのままで。。

とりあえずやってみよう!
今回は
- アプリ名
- bundle id
を指定します。
まずは先ほど自動生成できるようになったDart-Defines.xcconfig
を参照できるようにします。
#include "Generated.xcconfig"
+#include "Dart-Defines.xcconfig"
#include "Generated.xcconfig"
+#include "Dart-Defines.xcconfig"
BundleDisplayName
とBundleName
は直で記述されていたのでinfo.plist
の値をそれぞれ $(APP_NAME)
に変更しました。
Product Bundle Identifier
はBuild Settingsに大元の記述があるのでそちらを$(APP_ID)
に変更しました
これでビルドしてみましゅ!
....できたぁぁ!
アプリの識別IDが変わったから別アプリとして起動します。
アプリ名も開発・本番で変わってますね!後々アイコンも変えていきます

Flavor④ Android ①の変数を参照し設定する
androidは
android/app/build.gradle
-
android/app/src/main/AndroidManifest.xml
を編集します
+ def dartDefines = [:];
+ if (project.hasProperty('dart-defines')) {
+ // カンマ区切りかつBase64でエンコードされている dart-defines をデコードして変数に格納します。
+ dartDefines = dartDefines + project.property('dart-defines')
+ .split(',')
+ .collectEntries { entry ->
+ def pair = new String(entry.decodeBase64(), 'UTF-8').split('=')
+ pair.length == 2 ? [(pair.first()): pair.last()] : [:]
+ }
+ println(dartDefines)
+ }
defaultConfig {
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
- applicationId = "com.example.flutter_app_template"
+ applicationId "${dartDefines.APP_ID}"
+ resValue "string", "app_name", "${dartDefines.APP_NAME}"
}
<application
- android:label="flutter_app_template"
+ android:label="@string/app_name"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
これでそれぞれビルド!
開発、本番OKですね!
参考記事

環境ごとにアイコンを設定する
使用するパッケージはこちら
準備
assets/app_icons
配下に
- icon_dev.png
- icon_prod.png
を作成します。
次にこちらを参考にyamlファイルを作成します。プロジェクト直下でOKです。
flutter_launcher_icons:
image_path: "assets/app_icons/icon_dev.png"
android: "launcher_icon"
ios: true
remove_alpha_ios: true
flutter_launcher_icons:
image_path: "assets/app_icons/icon_prod.png"
android: "launcher_icon"
ios: true
remove_alpha_ios: true
あとは以下のコマンドをターミナルから叩きましょう。android,iOS用に画像が生成されます。
素晴らしい🎉
dart run flutter_launcher_icons
iOS
デフォルトではAppIcon
というアセットが指定されているので、AppIcon-$(FLAVOR)
で先ほど生成されたアセットを指定してあげるといいですね。
設定場所はTarget>Runner>Build Settings>Primary App Icon Set Name
になります。
編集を加えてビルドすると...🫨
Android
Androidはandroid/app/src/main/res
配下存在するアセットがアイコンとして設定されます。
flutter_launcher_iconにより生成したアセットはandroid/app/${FLAVOR}/res
に入っていますので、ビルド時にmain/resにコピーするコードをandroid/app/build.gradle
に記述します。
+ // Flavor アプリアイコンをmain/resへコピーする
+ task copySources(type: Copy) {
+ from "src/${dartDefines.FLAVOR}/res"
+ into 'src/main/res'
+ }
+ tasks.whenTaskAdded { task ->
+ task.dependsOn copySources
+ }
これでビルドすると...
あで??なんか四角いど??

Android アダプティブアイコン対応
四角になっていた原因はアダプティブアイコンに対応してない形式で作成していたのが原因みたいです。
気持ち悪い日本語のドキュメントをどうぞ↓
仕方がないので、新しいアイコンをFigmaでジェネレートしました。assets/app_icons/icon_adaptive.png
アダプティブアイコンの設定をymlファイルに記述します。
バックグラウンドはカラーコードで指定しました。
flutter_launcher_icons:
image_path: "assets/app_icons/icon_dev.png"
android: "launcher_icon"
ios: true
remove_alpha_ios: true
+ adaptive_icon_foreground: 'assets/app_icons/icon_adaptive.png'
+ adaptive_icon_background: '#7AABD9'
flutter_launcher_icons:
image_path: "assets/app_icons/icon_prod.png"
android: "launcher_icon"
ios: true
remove_alpha_ios: true
+ adaptive_icon_foreground: 'assets/app_icons/icon_adaptive.png'
+ adaptive_icon_background: '#F68C8C'
改めて、flutter_launcher_iconsの生成スクリプトを叩きます
dart run flutter_launcher_icons
ビルドします...
寝椅子ぅ🎉

疲れたな
次はスプラッシュマウンテンかなぁ🐳

Flutter スプラッシュ画面を作る
スプラッシュ画面はAndroid12から新しい手法となっているみたいでこれに対応しなければなりません。アプリアイコンの時から厄介ですねえ。
どうせflutterでやるなら一つの画像で全部賄いたい。それぞれの設定したくないなぁーできるかな?
android12含む全てのデバイス共通で利用できる画像を作る
アイコン背景は無しでそのままpng画像を表示しようと思うので、
1152px正方形の中に768の円を描いてその中に収まるようにスプラッシュ画像を作成します。
- App icon without an icon background, as shown on the left: This should be 1152×1152 pixels, and fit within a circle 768 pixels in diameter.
- App icon with an icon background, as shown on the right: This should be 960×960 pixels, and fit within a circle 640 pixels in diameter.
https://pub.dev/packages/flutter_native_splash#android-12-support
こんなもんか...!?
一旦これで背景色を消して、エクスポートします。
エクスポートした画像はassets/splash/splash.png
として配置しました。
スプラッシュ画像を生成する
以下コマンドでスプラッシュをジェネレート!
flutter pub run flutter_native_splash:create
特にこれ以上の設定は不要でビルドしたらスプラッシュが表示されます。
動作確認
スプラッシュは一瞬しか表示されないので、どこかに行ったらダメですよ。
Android
iOS
メモ
- 起動初期画面でデータの読み込み中はずっとスプラッシュ画面を表示するとか方法もありますが今回は割愛します。
- Flavorごとに変えたりもできますが、私はそこまでする必要ないだろう派なので割愛します。

ここまでmain.dartすらまだ一度も見ていません。これ以外のファイルもありません。
改めて開発準備段階でやること多いですねぇ。
現状:

とはいえここからやっとコードを書いていけそうですね!
ここまでのテンプレートでもだいぶ嬉しいです
続きはまた今度にしようかな