第5章
Firebaseを開発用と本番用に分ける
Firebase接続、認証、データ設計、Security Rules、開発用・本番用プロジェクトの切り替えを学びます。
この章で学ぶこと
- 開発用と本番用のFirebaseプロジェクトを分ける
- FlutterFireでWeb、Android、iOSの接続設定を作る
- Authentication、Firestore、Security Rulesを一緒に確認する
1. 2つのFirebaseプロジェクトを用意する
少なくとも次の2環境に分けます。
| 環境 | 例 | 用途 |
|---|---|---|
| development | idea-pocket-dev |
開発、エミュレーター、テストデータ |
| production | idea-pocket-prod |
公開アプリ、本番利用者 |
本番データを手元の実験で削除しないこと、開発中の通知やテスト利用者を本番へ混ぜないことが目的です。請求やAPIの上限も環境ごとに確認します。
2. FlutterFireで接続する
Firebase CLIとFlutterFire CLIを準備し、各自の招待済みGoogleアカウントでログインします。
firebase login
firebase projects:list
dart pub global activate flutterfire_cli
プロジェクトのルートで対象プラットフォームを設定します。
flutterfire configure \
--project=idea-pocket-dev \
--platforms=web,android,ios \
--out=lib/firebase_options_dev.dart
flutterfire configure \
--project=idea-pocket-prod \
--platforms=web,android,ios \
--out=lib/firebase_options_prod.dart
PowerShellで複数行がうまく解釈されない場合は、コマンドを1行で入力してください。生成された設定にはアプリがFirebaseへ接続するための識別情報が含まれますが、Admin SDKの秘密鍵や署名鍵を入れてはいけません。
生成ファイルはどちらもDefaultFirebaseOptionsというクラス名になるため、importに別名を付けます。起動時にビルド定義から環境を選ぶ例です。
import 'firebase_options_dev.dart' as dev;
import 'firebase_options_prod.dart' as prod;
const appEnv = String.fromEnvironment('APP_ENV', defaultValue: 'dev');
final options = appEnv == 'prod'
? prod.DefaultFirebaseOptions.currentPlatform
: dev.DefaultFirebaseOptions.currentPlatform;
await Firebase.initializeApp(options: options);
flutter run -d chrome --dart-define=APP_ENV=dev
flutter build web --release --dart-define=APP_ENV=prod
本番ビルドの既定値をdevにしておくと、指定忘れで誤った接続先になります。CIでは環境ごとにコマンドを固定し、ビルドログへProject IDを表示して確認します。
3. Authenticationを設定する
Firebase Consoleで各環境のAuthenticationを開き、必要なログイン方法だけを有効にします。Webでは承認済みドメイン、Googleログインでは同意画面、AppleログインではApple側のCapabilityや設定も必要になる場合があります。
最初の実習ではメール・パスワードまたは匿名認証のどちらか1つで十分です。利用者向けログイン方式と、開発チームがFirebase ConsoleへログインするGoogleアカウントは別物です。
ログイン状態を監視して画面を切り替えます。
StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
return snapshot.data == null ? const SignInPage() : const IdeaListPage();
},
)
4. FirestoreとSecurity Rulesを設定する
本人のカードだけを読み書きする最小ルール例です。
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId}/ideas/{ideaId} {
allow read, create, update, delete:
if request.auth != null && request.auth.uid == userId;
}
}
}
これは出発点です。作成時の必須フィールド、文字数、変更できない所有者IDなども検証します。画面でボタンを隠すだけでは、不正なリクエストを防げません。
ローカルのEmulator Suiteで、次を自動テストします。
- 未ログインでは拒否される。
- 利用者AはAのカードを作成・取得できる。
- 利用者AはBのカードを取得・変更できない。
- 必須項目の欠落や長すぎる文字列を拒否する。
ルールを本番へ反映するときは、対象を明示します。
firebase deploy --only firestore:rules --project idea-pocket-prod
デプロイ前にfirebase login:listとProject IDを確認してください。
5. App Check、予算、ログを準備する
公開前に、次を検討します。
- App Checkで正規アプリからのアクセスを検証する。
- Google Cloudの予算アラートを設定する。
- Authentication、Firestore、Functionsの利用量とエラーを確認する。
- Cloud Functionsで生成AI APIを呼ぶ場合は、認証、レート制限、タイムアウト、費用上限を入れる。
- 本番データを開発者が自由に閲覧しないようIAMを分ける。
予算アラートは利用を自動停止する仕組みとは限りません。急増時にどのサービスを止めるかも決めておきます。
やってみよう
- developmentとproductionのProject ID、アプリID、担当者を表にする。
- エミュレーターで、他人のカードを読めないテストを作る。
- developmentへ接続したWeb版で保存を確認する。
- 本番ビルドコマンドに
APP_ENV=prodが必ず含まれる仕組みを作る。