概要
Flutterでアプリをビルドする際には、本番環境と開発環境でGoogleService-info.plist等の設定ファイルの切り替えが必要となるケースが多いと思います。
この切替には複数のSchemeを用意する方法、Flavorを使う方法、ビルド時の--releaseと--debugを使って切り分ける方法がありますが、Flutter 1.17からビルド引数の--dart-defineで定数を渡せるようになりました。
この--dart-defineを使ってGoogleService-info.plistを切り替えてみましょう。
前提
- Flutterのサンプルプロジェクトを作成しシミュレーターで実行できる
- Flutter 1.20以降
-
--dart-defineの設定ができる(こちらの記事を参照)
環境
$ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 1.22.4, on Mac OS X 10.15.7 19H2 darwin-x64, locale en-JP)
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 12.1)
[✓] Android Studio (version 4.1)
[✓] Connected device (1 available)
iOS用の設定
iOSの場合、本番環境用と開発環境用のGoogleService-info.plistをビルド時のスクリプトで切り替える方法となります。
Flutterの設定
以下のように、コンパイル引数で渡します。
開発用
flutter build ios --dart-define=DEFINE_BUILD_ENV=dev
本番用
flutter build ios --dart-define=DEFINE_BUILD_ENV=prod
※ --dart-define の基本的な設定についてはこちらの記事を見てください。
Xcodeの設定
Runnerの中にFirebaseというフォルダを作り、その中にGoogleService-Info.plistを(開発用はGoogleService-Info-Dev.plist、本番用はGoogleService-Info-Prod.plistという名前で)追加します。

またRunnerディレクトリにGoogleService-Info.plistを追加しTargetに追加しておきます。(中身は開発用でも本番用でも、どちらでも大丈夫で、Keyだけ残して値は消してしまっても問題ありません。)
次にBuild Phasesを開き+を押してNew Run Script Phaseを追加します。名前をわかりやすいように変え、既存のRun Scriptの下に移動させます。(Script名をSelect Firebase Environmentとしました。)

Scriptに以下を追加します。定数については--dart-defineを使っています。設定についてはこちらの記事を参考にしてください。
if [[ $DEFINE_BUILD_ENV == *"dev"* ]]; then
cp $PRODUCT_NAME/Firebase/GoogleService-Info-Dev.plist $PRODUCT_NAME/GoogleService-Info.plist
elif [[ $DEFINE_BUILD_ENV == *"prod"* ]]; then
cp $PRODUCT_NAME/Firebase/GoogleService-Info-Prod.plist $PRODUCT_NAME/GoogleService-Info.plist
else
echo "configuration didn't match to 'dev' or 'prod'"
echo "Your DEFINE_BUILD_ENV is '$DEFINE_BUILD_ENV'"
exit 1
fi
動作確認
DEFINE_BUILD_ENVの値を開発用、本番用、どちでもない、で確認してみてください。どちらでもない値の場合はビルドエラーが発生し、エラーメッセージが表示されると思います。
android用の設定
androidの場合も、本番環境用と開発環境用のgoogle-services.jsonをビルド時のスクリプトで切り替える方法となります。
Flutterの設定
以下のように、コンパイル引数で渡します。
開発用
flutter build apk --dart-define=DEFINE_BUILD_ENV=dev
本番用
flutter build apk --dart-define=DEFINE_BUILD_ENV=prod
※ --dart-define の基本的な設定についてはこちらの記事を見てください。
gradleの設定
[project]/android/app/src/configを作成し、その中にdevとprodディレクトリを作成します。その中に、開発用、本番用のgoogle-services.jsonを設置します。

[project]/android/app/build.graldeを以下のように編集します。
// 〜〜 省略 〜〜
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
// ここから追記 --
def dartEnvironmentVariables = [
DEFINE_BUILD_ENV: 'dev',
];
if (project.hasProperty('dart-defines')) {
dartEnvironmentVariables = dartEnvironmentVariables + project.property('dart-defines')
.split(',')
.collectEntries { entry ->
def pair = URLDecoder.decode(entry).split('=')
[(pair.first()): pair.last()]
}
}
// firebaseファイルをコピーして android/app ディレクトリに移動
def googleServicesJson = "src/config/${dartEnvironmentVariables.DEFINE_BUILD_ENV}/google-services.json"
task copyGoogleServicesJson(type: Copy) {
from googleServicesJson
into './'
if(inputs.sourceFiles.empty){
throw new StopExecutionException("No files found: ${googleServicesJson}")
}
}
// firebaseファイルのコピータスクを待ってからファイルが必要な処理を行うよう設定
tasks.whenTaskAdded { task ->
if (task.name == 'processDebugGoogleServices') {
task.dependsOn copyGoogleServicesJson
}
if (task.name == 'processReleaseGoogleServices') {
task.dependsOn copyGoogleServicesJson
}
}
// ここまで追記 --
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
動作確認
DEFINE_BUILD_ENVの値を開発用、本番用、どちでもない、で確認してみてください。どちらでもない値の場合はビルドエラーが発生し、エラーメッセージが表示されると思います。