FlutterをFlavorで複数環境に分ける備忘録
前提
Flutter 3.27.2 既存のFlutterプロジェクトを複数環境に分ける Flavorを使って環境をdev, stg, prodに分ける Firebaseの設定も行う 実行はVSCodeを使うので、VSCodeの設定もする
初期化
android/ ios/ などのプラットフォームのディレクトリを全て消す。
flutter create .を実行してプラットフォームのファイルを作り直す。
Androidの設定
まずはAndroidの設定。iOSはめんどくさいのでひとまず無視。 Firebaseの設定もひとまずしない。 android/app/build.gradleにFlavorの設定を追加する。
android {
// ...
flavorDimensions "default"
productFlavors {
dev {
dimension "default"
resValue "string", "app_name", "App Dev"
applicationIdSuffix ".dev"
}
stg {
dimension "default"
resValue "string", "app_name", "App Stg"
applicationIdSuffix ".stg"
}
prod {
dimension "default"
resValue "string", "app_name", "App Prod"
}
}
}build.gradle.ktsの場合は
android {
...
flavorDimensions("default")
productFlavors {
create("dev") {
setDimension("default")
applicationIdSuffix = ".dev"
resValue("string", "app_name", "App Dev")
}
create("stg") {
setDimension("default")
applicationIdSuffix = ".stg"
resValue("string", "app_name", "App Stg")
}
create("prod") {
setDimension("default")
resValue("string", "app_name", "App Prod")
}
}
}しっかりFlavorが切り替わったことを確認するために、android/app/src/main/AndroidManifest.xmlを編集して、app_nameをFlavorによって変える処理を入れておく。
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="@string/app_name"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
VSCodeの設定
VSCodeの.vscode/launch.jsonを編集して、dev, stg, prodでの起動ができるようにしておく。 これで実行できるようにする。 モノレポなので、cwdを設定してるが、モノレポじゃなければ不要。
{
"version": "0.2.0",
"configurations": [
{
"name": "app(dev)(debug)",
"cwd": "packages/flutter_app",
"request": "launch",
"type": "dart",
"flutterMode": "debug",
"args": [
"--flavor",
"dev"
]
},
{
"name": "app(stg)(debug)",
"cwd": "packages/flutter_app",
"request": "launch",
"type": "dart",
"flutterMode": "debug",
"args": [
"--flavor",
"stg"
]
},
{
"name": "app(prod)(debug)",
"cwd": "packages/flutter_app",
"request": "launch",
"type": "dart",
"flutterMode": "debug",
"args": [
"--flavor",
"prod"
]
},
]
}Androidエミュレーターで実行してみると次のエラーが出たので、Androidの設定を修正。
┌─ Flutter Fix ─────────────────────────────────────────────────────────────────────────────────┐ │ The plugin firebase_auth requires a higher Android SDK version. │ │ Fix this issue by adding the following to the file │ │ /Users/fukui/Package/firebird/packages/firebird_app/android/app/build.gradle: │ │ android { │ │ defaultConfig { │ │ minSdkVersion 23 │ │ } │ │ } │ │ │ │ Following this change, your app will not be available to users running Android SDKs below 23. │ │ Consider searching for a version of this plugin that supports these lower versions of the │ │ Android SDK instead. │ │ For more information, see: https://flutter.dev/to/review-gradle-config │ └───────────────────────────────────────────────────────────────────────────────────────────────┘
android/app/build.gradleのminSdkVersionを23に変更する。
元々はminSdk = flutter.minSdkVersionだった。
android {
// .. │
│ defaultConfig {
// .. │
│ minSdkVersion = 23 │
│ } │
│ } build.gradle.kts
defaultConfig {
...
minSdkVersion(23)
...
}再度エミュレーターで実行してみる。 dev, stg, prodでそれぞれ起動してみてアプリ名が変わっていれば、Flavorの設定ができている。
iOSの設定
iOSの設定は少しだるいが、手順通りやれば大丈夫。 プロジェクトのルートで次のコマンドを実行して、XCodeを開く
open ios/Runner.xcworkspace左上のメニューからProduct > Scheme > New Schemeを選択する。 ダイアログが出てきて名前の入力を促されるので、devと入力してdevスキーマを作成する。 この名前がflavorに対応する。
次に、画面中央あたりにあるProjectのRunnerを選択。Infoというタブを探す。 Configurationsという項目の+ボタンを押す。 Duplicated "Debug" Configurationのような選択肢が出てくるので、Debug, Release, Profileを全てコピーする。
それぞれに名前をつけれるので、Debug-dev, Release-dev, Profile-devのようにしておく。
最後にメニューからProduct > Scheme > Manage Schemes...を選択し、先ほど作ったdevを選択する。 Run, Test, Profile, Analyze, ArchiveのBuild ConfigurationをDebugからDebug-devに変更する。
ProfileなどはProfile-devと設定としておく。
次にTARGETSのRunnerからBuild Settingのタブを探す。 All, Combinedを選択して、検索でproduct bundleと検索、Product Bundle Identifierの設定を変更する。 Debug-devの設定をcom.example.flutter-template.devとする。
またProduct Nameと検索してDebug-devの設定をApp Devにする。
Info.plistのBundle Display Nameの項目を$(PRODUCT_NAME)にする。
PodfileにDebug-devなどを追加する。 ついでにpodfileのiosバージョン設定を13にしておく platform :ios, '13.0'
platform :ios, '13.0'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
'Debug-dev' => :debug,
'Profile-dev' => :release,
'Release-dev' => :release,
}同様に、Stg, Prodスキーマも作成して設定する。
Firebaseの設定
flutterfireを利用して設定をおこなう。 設定するためのシェルスクリプトを作成しておく。これはプロジェクトのルートに配置。
#!/bin/bash
# Script to generate Firebase configuration files for different environments/flavors
# Feel free to reuse and adapt this script for your own projects
if [[ $# -eq 0 ]]; then
echo "Error: No environment specified. Use 'dev', 'stg', or 'prod'."
exit 1
fi
case $1 in
dev)
flutterfire config \
--project=flutter-template-dev \
--out=lib/firebase_options_dev.dart \
--ios-bundle-id=com.example.flutter-template.dev \
--ios-out=ios/flavors/dev/GoogleService-Info.plist \
--android-package-name=com.example.flutter_template.dev \
--android-out=android/app/src/dev/google-services.json
;;
stg)
flutterfire config \
--project=flutter-template-stg \
--out=lib/firebase_options_stg.dart \
--ios-bundle-id=com.example.flutter-template.stg \
--ios-out=ios/flavors/stg/GoogleService-Info.plist \
--android-package-name=com.example.flutter_template.stg \
--android-out=android/app/src/stg/google-services.json
;;
prod)
flutterfire config \
--project=flutter-template-prod \
--out=lib/firebase_options_prod.dart \
--ios-bundle-id=com.example.flutter-template \
--ios-out=ios/flavors/prod/GoogleService-Info.plist \
--android-package-name=com.example.flutter_template \
--android-out=android/app/src/prod/google-services.json
;;
*)
echo "Error: Invalid environment specified. Use 'dev', 'stg', or 'prod'."
exit 1
;;
esac権限がないので付与。
chmod +x packages/firebird_app/flutterfire-config.sh実行
./flutterfire-config.sh stg ✔ You have to choose a configuration type. Either build configuration (most likely choice) or a target set up. · Build configuration ✔ Please choose one of the following build configurations · Debug-stg
のように答えると、設定ファイルが追加される。
最後にDartでFlavorによって、Firebaesの初期化を分岐させる。
import 'package:template_app/firebase_options_dev.dart' as dev;
import 'package:template_app/firebase_options_prod.dart' as prod;
import 'package:template_app/firebase_options_stg.dart' as stg;
await Firebase.initializeApp(
options: switch (appFlavor) {
'dev' => dev.DefaultFirebaseOptions.currentPlatform,
'stg' => stg.DefaultFirebaseOptions.currentPlatform,
'prod' => prod.DefaultFirebaseOptions.currentPlatform,
_ => throw Exception('Invalid app flavor: $appFlavor'),
},
);