【Flutter】flutterfire_cli を使って Dart コードのみで環境分けする
変更履歴
2022/09/05 初版
2022/09/06 flutterfire_cli の隠しオプションについて追記(miyaken12 さんありがとうございます!)
2022/09/06 main.dart
で import as
を使うように変更
2022/09/06 GoogleService-Info.plist
や google-service.json
を削除できないかもしれない旨の注意書きを追加
2022/09/07 Android の アプリ名を Flavor に応じて切り替える説明を追加
2024/03/16 確認ができたので、Crashlytics、Analytics、Performance を使う場合は GoogleService-Info.plist
や google-service.json
を削除できない旨の注意書きに変更
2024/03/16 flutterfire configure
コマンドに --project
パラメータを追記
はじめに
Flutter × Firebase でアプリ作る場合、誤って本番環境を壊すなどの事故を起こさないために次のように環境分けをします。
環境名 | 説明 |
---|---|
開発環境 (dev) | 開発者が開発するときに使用 |
検証環境 (stg) | テスターがテストするときに使用、個人開発だと作らないことが多い |
本番環境 (prod) | ユーザーが使用 |
以前は GoogleService-Info.plist
や google-service.json
を Firebase からダウンロードし、各プラットフォーム向けに環境分けを構築していましたが、最近は flutterfire_cli を使えば簡単に Flutter × Firebase のセットアップが出来るようになりました。
しかし、flutterfire_cli は環境分け ( Flavor ) に対応していません。そこで本記事では flutterfire_cli を使って環境分けする方法 を紹介します!
また、Firebase プロジェクト情報を GoogleService-Info.plist
や google-service.json
を使わずに Dart コード ( FirebaseOptions
) のみで管理する方法 も合わせて紹介しています。
今回構築する環境分け
- 開発環境(dev)と本番環境(prod)の 2 系統
- Android / iOS の 2 つのプラットフォーム
-
GoogleService-Info.plist
やgoogle-service.json
を使わない - 環境に応じてパッケージ名やバンドル ID を分ける
- 環境に応じてアプリ名を分ける
環境
Flutter 3.3.0 • channel stable • https://github.com/flutter/flutter.git
Framework • revision ffccd96b62 (5 days ago) • 2022-08-29 17:28:57 -0700
Engine • revision 5e9e0e0aa8
Tools • Dart 2.18.0 • DevTools 2.15.0
Flutter アプリを新規に作成する
まず、次のコマンドで Flutter アプリを新規に作成します。--org jp.susatthi
は組織名なので適宜変更してください。
flutter create flutterfire-sample \
--org jp.susatthi \
--project-name flutterfire_sample \
--platforms ios,android
Flutter アプリ単体の環境分けをする
Firebase と連携をする前に、まずは Flutter アプリ単体の環境分けをします。
Flutter の環境分けの方法
Flutter で環境分けをしたい場合は、起動時のオプションに --flavor <flavor名>
をつけることで Android Gradle や Xcode の schemes に任意の <Flavor名>
を伝えることが出来ます。
flutter create --flavor の説明
しかし Dart のコードに伝えることは出来ないので --dart-define=FLAVOR=<flavor名>
と併用して使うことが多いです。
flutter create --dart-define の説明
例えば開発環境 (dev) と本番環境 (prod) の VS Code の起動設定は次のようになります。
{
"version": "0.2.0",
"configurations": [
{
"name": "mobile-dev",
"type": "dart",
"request": "launch",
"flutterMode": "debug",
"program": "lib/main.dart",
"args": [
"--flavor",
"dev",
"--dart-define=FLAVOR=dev",
]
},
{
"name": "mobile-prod",
"type": "dart",
"request": "launch",
"flutterMode": "debug",
"program": "lib/main.dart",
"args": [
"--flavor",
"prod",
"--dart-define=FLAVOR=prod",
]
}
]
}
--dart-define
だけで環境分けをしたい場合は次の記事が参考になります。
Android アプリの環境分けをする
Android アプリの環境分けをしていきます。
起動時の Flavor 指定に応じてパッケージ名とアプリ名を次のように分けてみます。
項目 | 開発環境 | 本番環境 |
---|---|---|
パッケージ名 | jp.susatthi.flutterfire_sample.dev | jp.susatthi.flutterfire_sample |
アプリ名 | (d)FlutterFire | FlutterFire |
android/app/build.gradle
を次のように修正します。
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
+ flavorDimensions 'flavor'
+ productFlavors {
+ dev {
+ dimension 'flavor'
+ applicationIdSuffix '.dev'
+ manifestPlaceholders = [appName: '(d)FlutterFire']
+ }
+ prod {
+ dimension 'flavor'
+ applicationIdSuffix ''
+ manifestPlaceholders = [appName: 'FlutterFire']
+ }
+ }
}
Flavor に応じてアプリ名を切り替えるために、次のように appName
を参照するように変更します。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="jp.susatthi.flutterfire_sample">
<application
- android:label="flutterfire_sample"
+ android:label="${appName}"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
これで Android アプリの環境分けが終わりました。Android は簡単ですね!
iOS アプリの環境分けをする
iOS アプリの環境分けをしていきます。
起動時の Flavor 指定に応じてバンドル名とアプリ名を次のように分けてみます。
項目 | 開発環境 | 本番環境 |
---|---|---|
バンドル名 | jp.susatthi.flutterfireSample.dev | jp.susatthi.flutterfireSample |
アプリ名 | (d)FlutterFire | FlutterFire |
iOS の環境分けは Xcode を使うので、次のコマンドで Xcode を起動します。
open ios/Runner.xcworkspace
iOS は Flavor に応じた schemes を作成する必要があります。そのために、まずは次の 4 種類の Configurations を作成します。
- Debug × dev
- Debug × prod
- Release × dev
- Release × prod
さらに、Configurations に紐付けるための xcconfig
ファイルを作成します。すでに Debug.xcconfig
と Release.xcconfig
は用意されているので、dev.xcconfig
と prod.xcconfig
を作成した後にそれらの組み合わせた 4 種類の xcconfig
ファイルを作成します。作成後は次のようになります。
それぞれの中身は次の通りです。
FLUTTER_FLAVOR=dev
PRODUCT_BUNDLE_IDENTIFIER=jp.susatthi.flutterfireSample.dev
DISPLAY_NAME=(d)FlutterFire
FLUTTER_TARGET=lib/main.dart
FLUTTER_FLAVOR=prod
PRODUCT_BUNDLE_IDENTIFIER=jp.susatthi.flutterfireSample
DISPLAY_NAME=FlutterFire
FLUTTER_TARGET=lib/main.dart
#include "Debug.xcconfig"
#include "dev.xcconfig"
#include "Debug.xcconfig"
#include "prod.xcconfig"
#include "Release.xcconfig"
#include "dev.xcconfig"
#include "Release.xcconfig"
#include "prod.xcconfig"
上で作成した xcconfig
ファイルを使って次のように Configurations を作成します。
Project Runner > Info > Configurations
次に Configurations を使って以下のように 2 つの schemes を作成します。
dev | prod |
---|---|
Flavor に応じてバンドルIDを切り替えるために、ビルド設定の Product Bundle Identifier に、次のように PRODUCT_BUNDLE_IDENTIFIER
を参照するように変更します。
Targets Runner > Build Settings
Flavor に応じてアプリ名を切り替えるために、次のように DISPLAY_NAME
を参照するように変更します。
Targets Runner > Info
これで iOS アプリの環境分けが終わりました。
Firebase プロジェクトを作成する
flutterfire_cli を使って開発環境と本番環境の Firebase プロジェクトを作成していきます。
次のコマンドを実行して flutterfire_cli をインストールしておきます。
dart pub global activate flutterfire_cli
開発環境の Firebase プロジェクトを作成する
まずは次のコマンドで開発環境の Firebase プロジェクトを作成します。各オプションの説明は flutterfire configure -h
で確認してみてください。
flutterfire configure \
--project=flutterfire-sample1-dev \
--out=lib/firebase_options_dev.dart \
--platforms=android,ios \
--ios-bundle-id=jp.susatthi.flutterfireSample.dev \
--android-package-name=jp.susatthi.flutterfire_sample.dev
上記のコマンドを実行すると一番最初に既存プロジェクトを選択しますが、今回新たにプロジェクトを作成したいので <create a new project>
を選択して「flutterfire-sample1-dev」という名前にします。
途中で android/build.gradle & android/app/build.gradle
を更新するか?と聞かれるので yes と答えておきます。
これで開発環境の Firebase プロジェクトが作成できました。
本番環境の Firebase プロジェクトを作成する
開発環境と同様に本番環境の Firebase プロジェクト「flutterfire-sample1-prod」を作成します。
flutterfire configure \
--project=flutterfire-sample1-prod \
--out=lib/firebase_options_prod.dart \
--platforms=android,ios \
--ios-bundle-id=jp.susatthi.flutterfireSample \
--android-package-name=jp.susatthi.flutterfire_sample
上記のコマンドを実行すると ios/firebase_app_id_file.json
と android/app/google-services.json
を上書きするか聞かれますが、あとで削除するので yes と答えておきます。
これで本番環境の Firebase プロジェクトが作成できました。
Firebase プロジェクトの設定変更
今回動作確認のために匿名認証のサインインを実装しますので、開発環境と本番環境の Firebase プロジェクトのコンソールの Authentication を開いて、匿名認証を有効化しておきます。
Flutter アプリと Firebase を連携させる
Flutter アプリと Firebase と連携させて、デフォルトのカウントアップアプリを起動したときに匿名認証でサインインする機能を実装してみます。
Firebase のパッケージをインストールする
pubspec.yaml
を修正して firebase_core と firebase_auth をインストールします。忘れずに flutter pub get
をしましょう。
dependencies:
flutter:
sdk: flutter
+ firebase_core: ^1.21.1
+ firebase_auth: ^3.7.0
匿名認証でサインインする
アプリ起動時に未サインインなら匿名認証でサインインする実装をします。--dart-define=FLAVOR=<flavor名>
で与えられた flavor名
を String.fromEnvironment('FLAVOR')
で受け取って FirebaseOptions
を切り替えています。
今回は flavor
を文字列で扱っていますが、enum
を使ったほうがよりスッキリ書けると思います。
+import 'package:firebase_auth/firebase_auth.dart';
+import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
+import 'package:flutterfire_sample/firebase_options_dev.dart' as dev;
+import 'package:flutterfire_sample/firebase_options_prod.dart' as prod;
+
+const flavor = String.fromEnvironment('FLAVOR');
+
-void main() {
+Future<void> main() async {
+ WidgetsFlutterBinding.ensureInitialized();
+
+ // Flavor に応じた FirebaseOptions を準備する
+ final firebaseOptions = flavor == 'prod'
+ ? prod.DefaultFirebaseOptions.currentPlatform
+ : dev.DefaultFirebaseOptions.currentPlatform;
+
+ // Firebase の初期化
+ await Firebase.initializeApp(
+ options: firebaseOptions,
+ );
+
+ // FirebaseUser を取得する
+ final firebaseUser = await FirebaseAuth.instance.userChanges().first;
+ print('uid = ${firebaseUser?.uid}');
+ if (firebaseUser == null) {
+ // 未サインインなら匿名ユーザーでサインインする
+ final credential = await FirebaseAuth.instance.signInAnonymously();
+ final uid = credential.user!.uid;
+ print('Signed in: uid = $uid');
+ }
runApp(const MyApp());
}
不要なファイルを削除・修正する
Dart コードで Firebase プロジェクト情報を管理することが出来たので、次のファイルは削除しちゃいます。
android/app/google-services.json
ios/firebase_app_id_file.json
また、Android ビルド時に google-services.json
を探す処理をしている apply plugin: 'com.google.gms.google-services'
を build.gradle
から削除します。
- // START: FlutterFire Configuration
- apply plugin: 'com.google.gms.google-services'
- // END: FlutterFire Configuration
Xcode で iOS プロジェクトを開いて、GoogleService-Info.plist
も削除しちゃいます。
以上ですべて完了です!Dart コードのみで管理できるようになってかなりスッキリしました!
サンプルコードを公開しています
今回ご紹介したサンプルコードを公開しています。是非参考にしてください!
最後に
Flutter 大学という Flutter エンジニアに特化した学習コミュニティに所属しています。オンラインでわいわい議論したり、Flutter の最新情報をゲットしたりできます!ぜひ Flutter 界隈を盛り上げていきましょう!
あわせて読みたい
Discussion
良かったら
flutterfire configure
時に以下オプションを使ってみてください!flutterfire_cli 0.2.4で動作確認できましてgradleの更新やfirebase_app_id_file.jsonファイルの生成は防いでくれます
ドキュメントの整備が落ち着いてなく、隠しオプションがあるっぽいです↓
また、Firebase公式がドキュメント化してなく別の方が隠しオプションを含めた記事を最近書いたものもありますので参考になればです!(Flutter公式のFlavor対応のリンク集一覧にもある↓)
コメントありがとうございます!試してみたら確かに教えて頂いたとおりの動きをしました!隠しオプションについて追記させて頂きました!