Firebase Emulator Suite を使用した Flutter アプリのローカル開発

1. 始める前に

この Codelab では、ローカルでの開発中に Flutter で Firebase Emulator Suite を使用する方法を学びます。Emulator Suite を介してメールとパスワードによる認証を使用する方法と、Firestore エミュレータに対してデータの読み取りと書き込みを行う方法について学習します。最後に、エミュレータからデータをインポートおよびエクスポートして、開発に戻るたびに同じ偽装データを使用できるようにします。

前提条件

この Codelab は、Flutter の使用経験があることを前提としています。まだの場合は、まず基本的な使い方を学習してください。次のリンクが役に立ちます。

Firebase の使用経験も必要ですが、Flutter プロジェクトに Firebase を追加したことがなくても大丈夫です。Firebase コンソールに馴染みがない方や、Firebase を初めて使用する場合は、まず次のリンクをご覧ください。

作成するアプリの概要

この Codelab では、簡単なジャーナリング アプリケーションの作成について説明します。アプリケーションにはログイン画面があります。また、過去の記録を読んだり、新しい記録を作成したりすることができます。

cd5c4753bbee8af.png 8cb4d21f656540bf.png

学習内容

Firebase の使用を開始する方法と、Firebase Emulator Suite を Flutter 開発ワークフローに統合して使用する方法について学びます。ここでは、Firebase の以下のトピックを扱います。

これらのトピックについては、Firebase Emulator Suite で必要な範囲で説明します。この Codelab では、Firebase プロジェクトを Flutter アプリに追加し、Firebase エミュレータ スイートを使用して開発する方法について説明します。Firebase Authentication や Firestore について詳しく説明することはありません。これらのトピックに詳しくない場合は、Flutter 向けの Firebase に関する Codelab から始めることをおすすめします。

必要なもの

  • Flutter の基本的な知識と SDK がインストールされている
  • Intellij JetBrains または VS Code テキスト エディタ
  • Google Chrome ブラウザ(または Flutter の他の開発ターゲット)。この Codelab の一部のターミナル コマンドは、アプリが Chrome で実行されていることを前提としています)。

2. Firebase プロジェクトを作成して設定する

最初に、Firebase のウェブ コンソールで Firebase プロジェクトを作成する必要があります。この Codelab の大部分では、ローカルで実行される UI を使用する Emulator Suite について説明しますが、まず Firebase プロジェクト全体を設定する必要があります。

Firebase プロジェクトを作成する

  1. Firebase コンソールにログインします。
  2. Firebase コンソールで [プロジェクトを追加](または [プロジェクトを作成])をクリックし、Firebase プロジェクトの名前(例: Firebase-Flutter-Codelab)を入力します。

fe6aeab3b91965ed.png

  1. プロジェクト作成オプションをクリックします。プロンプトが表示されたら、Firebase の利用規約に同意します。このアプリではアナリティクスを使用しないため、Google アナリティクスの設定はスキップします。

d1fcec48bf251eaa.png

Firebase プロジェクトの詳細については、Firebase プロジェクトについて理解するをご覧ください。

これから構築するアプリでは、Flutter アプリで使用できる 2 つの Firebase プロダクトを使用します。

  • Firebase Authentication: ユーザーがアプリにログインできるようにします。
  • 構造化データをクラウドに保存し、データが変更されたときに即座に通知を受け取る Cloud Firestore

これら 2 つのプロダクトは、特別な構成が必要であるか、Firebase コンソールを使用して有効にする必要があります。

Cloud Firestore の有効化

Flutter アプリは Cloud Firestore を使用してジャーナルのエントリを保存します。

Cloud Firestore を有効にします。

  1. Firebase コンソールの [構築] セクションで、[Cloud Firestore] をクリックします。
  2. [データベースを作成] をクリックします。99e8429832d23fa3.png
  3. [テストモードで開始] オプションを選択します。セキュリティ ルールに関する免責条項をお読みください。テストモードでは、開発中にデータベースに自由に書き込めます。[次へ] をクリックします。6be00e26c72ea032.png
  4. データベースの場所を選択します(デフォルトをそのまま使用することもできます)。この場所を後から変更することはできません。278656eefcfb0216.png
  5. [有効にする] をクリックします。

3. Flutter アプリを設定する

始める前に、スターター コードをダウンロードして Firebase CLI をインストールする必要があります。

スターター コードを取得する

コマンドラインから、GitHub リポジトリのクローンを作成します。

git clone https://github.com/flutter/codelabs.git flutter-codelabs

または、GitHub の cli ツールがインストールされている場合は、次のコマンドを使用します。

gh repo clone flutter/codelabs flutter-codelabs

サンプルコードのクローンは、Codelab のコレクションのコードを含む flutter-codelabs ディレクトリに作成する必要があります。この Codelab のコードは flutter-codelabs/firebase-emulator-suite にあります。

flutter-codelabs/firebase-emulator-suite の下のディレクトリ構造は、2 つの Flutter プロジェクトで構成されています。そのうちの 1 つは complete と呼ばれ、先に進む場合、または独自のコードを相互参照する場合に参照できます。もう一方のプロジェクトは start と呼ばれます。

開始するコードは flutter-codelabs/firebase-emulator-suite/start ディレクトリにあります。そのディレクトリを任意の IDE で開くか、インポートします。

cd flutter-codelabs/firebase-emulator-suite/start

Firebase CLI のインストール

Firebase CLI には、Firebase プロジェクトを管理するためのツールが用意されています。Emulator Suite を使用するには CLI が必要なため、インストールする必要があります。

CLI をインストールする方法はいくつかあります。MacOS または Linux を使用している場合は、ターミナルから次のコマンドを実行するのが最も簡単な方法です。

curl -sL https://firebase.tools | bash

CLI をインストールしたら、Firebase で認証する必要があります。

  1. Google アカウントで Firebase にログインするには、次のコマンドを実行します。
firebase login
  1. このコマンドを実行すると、ローカルマシンが Firebase に接続され、Firebase プロジェクトにアクセスできるようになります。
  1. Firebase プロジェクトを一覧表示し、CLI が正しくインストールされていて、アカウントにアクセスできることをテストします。次のコマンドを実行します。
firebase projects:list
  1. 表示される一覧は、Firebase コンソールに表示されているものと同じ Firebase プロジェクトが表示されているはずです。少なくとも firebase-flutter-codelab が表示されます。

FlutterFire CLI をインストールする

FlutterFire CLI は Firebase CLI 上に構築されており、Firebase プロジェクトと Flutter アプリの統合を容易にします。

まず、CLI をインストールします。

dart pub global activate flutterfire_cli

CLI がインストールされていることを確認します。Flutter プロジェクト ディレクトリで次のコマンドを実行し、CLI がヘルプメニューを出力することを確認します。

flutterfire --help

Firebase CLI と FlutterFire CLI を使用して Firebase プロジェクトを Flutter アプリに追加する

2 つの CLI をインストールすると、個々の Firebase プロダクト(Firestore など)を設定したり、エミュレータをダウンロードしたり、Firebase を Flutter アプリに追加したりできます。これは、いくつかのターミナル コマンドで行うことができます。

まず、次のコマンドを実行して Firebase の設定を完了します。

firebase init

このコマンドを実行すると、プロジェクトの設定に必要な一連の質問が表示されます。以下のスクリーンショットはフローを示しています。

  1. 特徴を選択するように求められたら、[Firestore] を選択します。「エミュレータ」です。(Flutter プロジェクト ファイルから変更可能な構成を使用しないため、認証オプションはありません)。fe6401d769be8f53.png
  2. 次に、プロンプトが表示されたら [既存のプロジェクトを使用する] を選択します。

f11dcab439e6ac1e.png

  1. 前の手順で作成したプロジェクト(flutter-firebase-codelab)を選択します。

3bdc0c6934991c25.png

  1. 次に、生成されるファイルの名前付けに関する一連の質問が表示されます。Enter を押すことをおすすめしますデフォルトを選択します。9bfa2d507e199c59.png
  2. 最後に、エミュレータを構成する必要があります。リストから Firestore と Authentication を選択し、各エミュレータで使用する特定のポートを尋ねる質問ごとに Enter キーを押します。Emulator UI を使用するかどうかを尋ねられたら、デフォルトの [Yes] を選択する必要があります。

プロセスが終了すると、次のスクリーンショットのような出力が表示されます。

重要: エミュレータがすでにダウンロードされている場合、最後の質問はデフォルトで「いいえ」になります。そのため、出力は下のスクリーンショットとは若干異なる場合があります。

8544e41037637b07.png

FlutterFire を構成する

次に、FlutterFire を使用して、Flutter アプリで Firebase を使用するために必要な Dart コードを生成します。

flutterfire configure

このコマンドを実行すると、使用する Firebase プロジェクトと設定するプラットフォームを選択するよう求められます。この Codelab の例では Flutter Web を使用していますが、すべてのオプションを使用するように Firebase プロジェクトをセットアップすることもできます。

次のスクリーンショットは、回答が必要なプロンプトを示しています。

619b7aca6dc15472.png 301c9534f594f472.png

このスクリーンショットは、プロセスの終了時の出力を示しています。Firebase に精通している方は、コンソールでアプリケーションを作成する必要はなく、FlutterFire CLI が作成したことに気付くでしょう。

12199a85ade30459.png

Flutter アプリに Firebase パッケージを追加する

設定の最後のステップは、関連する Firebase パッケージを Flutter プロジェクトに追加することです。ターミナルで、Flutter プロジェクトのルート(flutter-codelabs/firebase-emulator-suite/start)にいることを確認します。次に、次の 3 つのコマンドを実行します。

flutter pub add firebase_core
flutter pub add firebase_auth
flutter pub add cloud_firestore

このアプリケーションで使用するパッケージは、これだけです。

4. Firebase エミュレータを有効にする

ここまでで、Flutter アプリと Firebase プロジェクトはエミュレータを使用できるように設定されていますが、送信される Firebase リクエストをローカルポートに再ルーティングするように Flutter コードに指示する必要があります。

まず、Firebase の初期化コードとエミュレータのセットアップ コードを main.dart.main 関数に追加します。

main.dart

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

import 'app_state.dart';
import 'firebase_options.dart';
import 'logged_in_view.dart';
import 'logged_out_view.dart';


void main() async {
 WidgetsFlutterBinding.ensureInitialized();
 await Firebase.initializeApp(
   options: DefaultFirebaseOptions.currentPlatform,
 );

 if (kDebugMode) {
   try {
     FirebaseFirestore.instance.useFirestoreEmulator('localhost', 8080);
     await FirebaseAuth.instance.useAuthEmulator('localhost', 9099);
   } catch (e) {
     // ignore: avoid_print
     print(e);
   }
 }

 runApp(MyApp());
}

コードの最初の数行で Firebase を初期化します。ほぼ例外なく、Flutter アプリで Firebase を使用する場合、最初に WidgetsFlutterBinding.ensureInitializedFirebase.initializeApp を呼び出す必要があります。

その後、if (kDebugMode) 行で始まるコードは、本番環境の Firebase プロジェクトではなくエミュレータをターゲットにするようにアプリに指示します。kDebugMode により、エミュレータのターゲティングは開発環境にいる場合にのみ行われるようになります。kDebugMode は定数値であるため、Dart コンパイラはリリースモードでそのコードブロックを完全に削除します。

エミュレータを起動する

Flutter アプリを起動する前に、エミュレータを起動する必要があります。まず、ターミナルで次のコマンドを実行してエミュレータを起動します。

firebase emulators:start

このコマンドはエミュレータを起動し、エミュレータとやり取りできる localhost ポートを公開します。このコマンドを実行すると、次のような出力が表示されます。

bb7181eb70829606.png

この出力により、実行中のエミュレータと、エミュレータを表示できる場所がわかります。まず、localhost:4000 でエミュレータ UI を確認します。

11563f4c7216de81.png

ローカル エミュレータの UI のホームページです。利用可能なエミュレータがすべて一覧表示され、各エミュレータにオンとオフのラベルが付けられています。

5. Firebase Auth エミュレータ

最初に使用するエミュレータは、Authentication エミュレータです。まず、UI の [Authentication] カードで [エミュレータに移動] をクリックして、Auth エミュレータを起動します。次のようなページが表示されます。

3c1bfded40733189.png

このページは、Auth ウェブ コンソール ページと類似しています。オンライン コンソールと同様に、ユーザーが一覧表示されるテーブルがあり、手動でユーザーを追加できます。ここでの大きな違いは、エミュレータで使用できる認証方法のオプションがメールとパスワードのみであることです。ローカルでの開発にはこれで十分です。

次に、Firebase Auth エミュレータにユーザーを追加し、そのユーザーを Flutter UI からログインするプロセスについて説明します。

ユーザーを追加する

[ユーザーを追加] ボタンをクリックし、次の情報をフォームに入力します。

  • 表示名: Dash
  • メール: dash@email.com
  • パスワード: ダッシュワード

フォームを送信すると、テーブルにユーザーが追加されます。これで、そのユーザーでログインするようにコードを更新できます。

logged_out_view.dart

更新が必要な LoggedOutView ウィジェットのコードは、ユーザーがログインボタンを押したときにトリガーされるコールバックにのみ存在します。コードを次のように更新します。

class LoggedOutView extends StatelessWidget {
 final AppState state;
 const LoggedOutView({super.key, required this.state});
 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(
       title: const Text('Firebase Emulator Suite Codelab'),
     ),
     body: Center(
       child: Column(
         mainAxisAlignment: MainAxisAlignment.center,
         children: [
          Text(
           'Please log in',
            style: Theme.of(context).textTheme.displaySmall,
          ),
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: ElevatedButton(
             onPressed: () async {
              await state.logIn('dash@email.com', 'dashword').then((_) {
                if (state.user != null) {
                 context.go('/');
                }
              });
              },
              child: const Text('Log In'),
          ),
        ),
      ],
    ),
   ),
  );
 }
}

更新されたコードにより、TODO の文字列は、auth エミュレータで作成したメールアドレスとパスワードに置き換えられます。また、次の行では、if(true) 行が、state.user が null かどうかを確認するコードに置き換えられています。この問題については、AppClass のコードで確認できます。

app_state.dart

AppState のコードの 2 つの部分を更新する必要があります。まず、クラス メンバー AppState.user に、Object タイプではなく firebase_auth パッケージの User タイプを指定します。

次に、AppState.login メソッドに次のように入力します。

import 'dart:async';

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';

import 'entry.dart';

class AppState {
 AppState() {
   _entriesStreamController = StreamController.broadcast(onListen: () {
     _entriesStreamController.add([
       Entry(
         date: '10/09/2022',
         text: lorem,
         title: '[Example] My Journal Entry',
       )
     ]);
   });
 }

 User? user; // <-- changed variable type
 Stream<List<Entry>> get entries => _entriesStreamController.stream;
 late final StreamController<List<Entry>> _entriesStreamController;

 Future<void> logIn(String email, String password) async {
   final credential = await FirebaseAuth.instance
       .signInWithEmailAndPassword(email: email, password: password);
   if (credential.user != null) {
     user = credential.user!;
     _listenForEntries();
   } else {
     print('no user!');
   }
 } 
 // ...
}

ユーザーのタイプ定義は User? になりました。この User クラスは Firebase Auth から取得され、User.displayName などの必要な情報を提供します。User.displayName については後で説明します。

これは、Firebase Auth でメールアドレスとパスワードを使用してユーザーがログインするために必要な基本的なコードです。FirebaseAuth を呼び出してログインし、Future<UserCredential> オブジェクトを返します。フューチャーが完了すると、このコードは UserCredentialUser が関連付けられているかどうかを確認します。認証情報オブジェクトにユーザーが存在する場合、ユーザーは正常にログインしており、AppState.user プロパティを設定できます。ない場合は、エラーが発生し、エラーが印刷されます。

このメソッドで(一般的な FirebaseAuth コードではなく)このアプリに固有のコード行は、_listenForEntries メソッドの呼び出しのみです。このメソッドについては、次のステップで説明します。

TODO: アクション アイコン - アプリを再読み込みし、レンダリングされたらログインボタンを押します。これにより、アプリは上部に「ようこそ、ユーザーさん」と表示されたページに移動します。このページに移動できるため、認証は機能しているはずですが、ユーザーの実際の名前を表示するには logged_in_view.dart に軽微な更新が必要です。

logged_in_view.dart

LoggedInView.build メソッドの最初の行を変更します。

class LoggedInView extends StatelessWidget {
 final AppState state;
 LoggedInView({super.key, required this.state});

 final PageController _controller = PageController(initialPage: 1);

 @override
 Widget build(BuildContext context) {
   final name = state.user!.displayName ?? 'No Name';

   return Scaffold(
 // ...

この行は、AppState オブジェクトの User プロパティから displayName を取得します。この displayName は、最初のユーザーを定義したときにエミュレータで設定されました。これで、アプリに「Welcome back, Dash!」ログイン時に使用します(TODO ではありません)。

6. Firestore エミュレータへのデータの読み取りと書き込み

まず、Firestore エミュレータを確認します。エミュレータ UI のホームページ(localhost:4000)で、Firestore カードの [エミュレータに移動] をクリックします。次のようになります。

エミュレータ:

791fce7dc137910a.png

Firebase コンソール:

e0dde9aea34af050.png

Firestore を使用したことがある場合は、このページが Firebase コンソールの Firestore ページに似ていることに気付くでしょう。ただし、次のような大きな違いがあります。

  1. ボタンをタップするだけで、すべてのデータを消去できます。これは本番環境データでは危険ですが、迅速なイテレーションに役立ちます。新しいプロジェクトに取り組んでいて、データモデルが変更された場合、簡単に消去できます。
  2. [Requests]にはタブこのタブでは、このエミュレータに対する受信リクエストをモニタリングできます。このタブについて詳しくは後述します。
  3. [ルール]、[インデックス]、[使用状況] のタブはありません。セキュリティ ルールの作成に役立つツール(次のセクションで説明)はありますが、ローカル エミュレータのセキュリティ ルールを設定することはできません。

以上をまとめると、このバージョンの Firestore では、開発時に利用できるツールが増え、本番環境では必要なツールが削除されています。

Firestore に書き込む

エミュレータの [リクエスト] タブについて説明する前に、まずリクエストを送信します。これにはコードの更新が必要です。まず、新しいジャーナル Entry を Firestore に書き込むように、アプリにフォームを設定します。

Entry を送信する大まかな流れは次のとおりです。

  1. ユーザーがフォームに記入し、Submit ボタンを押しました
  2. UI が AppState.writeEntryToFirebase を呼び出す
  3. AppState.writeEntryToFirebase が Firebase にエントリを追加します。

ステップ 1 または 2 のコードは変更する必要はありません。ステップ 3 で追加する必要があるコードは、AppState クラスのみに追加します。AppState.writeEntryToFirebase に次の変更を加えます。

app_state.dart

import 'dart:async';

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';

import 'entry.dart';

class AppState {
 AppState() {
   _entriesStreamController = StreamController.broadcast(onListen: () {
     _entriesStreamController.add([
       Entry(
         date: '10/09/2022',
         text: lorem,
         title: '[Example] My Journal Entry',
       )
     ]);
   });
 }

 User? user;
 Stream<List<Entry>> get entries => _entriesStreamController.stream;
 late final StreamController<List<Entry>> _entriesStreamController;

 Future<void> logIn(String email, String password) async {
   final credential = await FirebaseAuth.instance
       .signInWithEmailAndPassword(email: email, password: password);
   if (credential.user != null) {
     user = credential.user!;
     _listenForEntries();
   } else {
     print('no user!');
   }
 }

 void writeEntryToFirebase(Entry entry) {
   FirebaseFirestore.instance.collection('Entries').add(<String, String>{
     'title': entry.title,
     'date': entry.date.toString(),
     'text': entry.text,
   });
 }
 // ...
}

writeEntryToFirebase メソッドのコードは、Entries という名前のコレクションへの参照を取得します。Firestore です次に、新しいエントリを追加します。このエントリは Map<String, String> 型にする必要があります。

この場合、Firestore の「エントリ」コレクションが存在しないため、Firestore によって作成されました。

コードを追加したら、アプリをホットリロードまたは再起動してログインし、EntryForm ビューに移動します。フォームには任意の Strings を入力できます。(この Codelab では簡略化されているため、Date フィールドには任意の文字列を指定できます。強力な検証は行われず、DateTime オブジェクトもまったく考慮されません)。

フォームの送信ボタンを押します。アプリには何も起こりませんが、エミュレータ UI に新しいエントリが表示されます。

Firestore エミュレータの [Requests] タブ

UI で Firestore エミュレータに移動し、[Data] ビューを確認します。タブデータベースのルートに「Entries」という名前のコレクションが作成されていることがわかります。フォームに入力した情報と同じ情報が記載された書類が表示されます。

a978fb34fb8a83da.png

これで、AppState.writeEntryToFirestore が機能したことが確認できました。[リクエスト] タブでリクエストを詳しく確認できます。それでは、タブをクリックしましょう。

Firestore エミュレータ リクエスト

次のようなリストが表示されます。

f0b37f0341639035.png

リスト内の項目をクリックすると、役立つ情報が多数表示されます。リクエストに対応する CREATE リストアイテムをクリックして、新しいジャーナル エントリを作成します。次のような新しい表が表示されます。

385d62152e99aad4.png

前述のとおり、Firestore エミュレータには、アプリのセキュリティ ルールを開発するためのツールが用意されています。このビューには、このリクエストがセキュリティ ルールのどの行を通過したか(または失敗したか)が正確に示されます。より堅牢なアプリでは、セキュリティ ルールが拡張され、複数の承認チェックが含まれる場合があります。このビューは、これらの認可ルールの作成とデバッグに使用されます。

また、メタデータや認証データなど、このリクエストのあらゆる部分を簡単に検査できます。このデータは、複雑な承認ルールの作成に使用されます。

Firestore からの読み取り

Firestore はデータ同期を使用して、更新されたデータをコネクテッド デバイスに push します。Flutter コードでは、Firestore コレクションとドキュメントをリッスン(またはサブスクライブ)できます。データが変更されると、コードに通知されます。このアプリでは、Firestore の更新のリッスンは AppState._listenForEntries というメソッドで行われます。

このコードは、それぞれ AppState._entriesStreamControllerAppState.entries と呼ばれる StreamControllerStream と連携して機能します。このコードは、Firestore のデータを表示するために UI に必要なすべてのコードと同様に、すでに作成されています。

_listenForEntries メソッドを次のように更新します。

app_state.dart

import 'dart:async';

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';

import 'entry.dart';

class AppState {
 AppState() {
   _entriesStreamController = StreamController.broadcast(onListen: () {
     _entriesStreamController.add([
       Entry(
         date: '10/09/2022',
         text: lorem,
         title: '[Example] My Journal Entry',
       )
     ]);
   });
 }

 User? user;
 Stream<List<Entry>> get entries => _entriesStreamController.stream;
 late final StreamController<List<Entry>> _entriesStreamController;

 Future<void> logIn(String email, String password) async {
   final credential = await FirebaseAuth.instance
       .signInWithEmailAndPassword(email: email, password: password);
   if (credential.user != null) {
     user = credential.user!;
     _listenForEntries();
   } else {
     print('no user!');
   }
 }

 void writeEntryToFirebase(Entry entry) {
   FirebaseFirestore.instance.collection('Entries').add(<String, String>{
     'title': entry.title,
     'date': entry.date.toString(),
     'text': entry.text,
   });
 }

 void _listenForEntries() {
   FirebaseFirestore.instance
       .collection('Entries')
       .snapshots()
       .listen((event) {
     final entries = event.docs.map((doc) {
       final data = doc.data();
       return Entry(
         date: data['date'] as String,
         text: data['text'] as String,
         title: data['title'] as String,
       );
     }).toList();

     _entriesStreamController.add(entries);
   });
 }
 // ...
}

このコードは "Entries" 変数をコレクションを作成します。Firestore は、このクライアントに新しいデータがあることを通知すると、そのデータを渡し、_listenForEntries のすべての子ドキュメントをアプリが使用できるオブジェクト(Entry)に変更します。次に、それらのエントリを _entriesStreamController という StreamController(UI がリッスンしている)に追加します。更新が必要なのはこのコードのみです。

最後に、AppState.logIn メソッドは _listenForEntries を呼び出します。これにより、ユーザーがログインした後にリッスン プロセスが開始されます。

// ...
Future<void> logIn(String email, String password) async {
 final credential = await FirebaseAuth.instance
     .signInWithEmailAndPassword(email: email, password: password);
 if (credential.user != null) {
   user = credential.user!;
   _listenForEntries();
 } else {
   print('no user!');
 }
}
// ...

アプリを実行すると、次のようになります。

b8a31c7a8900331.gif

7. エミュレータへのデータのエクスポートとインポート

Firebase エミュレータは、データのインポートとエクスポートをサポートしています。インポートとエクスポートを使用すると、開発を中断して再開する際に同じデータで開発を続行できます。データファイルを Git に commit することもできます。同じデータを共同で作業する他のデベロッパーと共同で作業できます。

エミュレータ データのエクスポート

まず、既存のエミュレータ データをエクスポートします。エミュレータが実行されている間に、新しいターミナル ウィンドウを開き、次のコマンドを入力します。

firebase emulators:export ./emulators_data

.emulators_data は、データをエクスポートする場所を Firebase に指示する引数です。ディレクトリが存在しない場合は作成されます。このディレクトリには任意の名前を使用できます。

このコマンドを実行すると、コマンドを実行したターミナルに次の出力が表示されます。

i  Found running emulator hub for project flutter-firebase-codelab-d6b79 at http://localhost:4400
i  Creating export directory /Users/ewindmill/Repos/codelabs/firebase-emulator-suite/complete/emulators_data
i  Exporting data to: /Users/ewindmill/Repos/codelabs/firebase-emulator-suite/complete/emulators_data
✔  Export complete

エミュレータが実行されているターミナル ウィンドウに切り替えると、次の出力が表示されます。

i  emulators: Received export request. Exporting data to /Users/ewindmill/Repos/codelabs/firebase-emulator-suite/complete/emulators_data.
✔  emulators: Export complete.

最後に、プロジェクト ディレクトリに ./emulators_data というディレクトリが表示されます。このディレクトリには、保存したデータを含む JSON ファイルなどのメタデータ ファイルが含まれています。

エミュレータ データのインポート

これで、そのデータを開発ワークフローの一部としてインポートし、中断したところから再開できるようになりました。

まず、エミュレータが実行されている場合は、ターミナルで CTRL+C を押してエミュレータを停止します。

次に、前に説明した emulators:start コマンドを実行します。その際、インポートするデータを指定するフラグを指定します。

firebase emulators:start --import ./emulators_data

エミュレータが起動したら、localhost:4000 にあるエミュレータ UI に移動します。以前に使用していたデータが表示されます。

エミュレータを閉じるときにデータを自動的にエクスポートする

開発セッションの終了時にデータをエクスポートすることを忘れないようにするのではなく、エミュレータを終了するときにデータを自動的にエクスポートすることもできます。

エミュレータを起動するときに、2 つのフラグを追加して emulators:start コマンドを実行します。

firebase emulators:start --import ./emulators_data --export-on-exit

必要な操作は以上です。これでデータが保存され、このプロジェクトのエミュレータを使用するたびに再読み込みされます。–export-on-exit flag の引数として別のディレクトリを指定することもできますが、デフォルトでは –import に渡されるディレクトリになります。

これらのオプションは自由に組み合わせて使用できます。ドキュメントの注: エクスポート ディレクトリは firebase emulators:start --export-on-exit=./saved-data フラグで指定できます。--import を使用する場合、エクスポート パスはデフォルトで同じになります。例: firebase emulators:start --import=./data-path --export-on-exit最後に、必要に応じて、--import フラグと --export-on-exit フラグに異なるディレクトリ パスを渡します。

8. 完了

これで、Firebase エミュレータと Flutter を使ってアプリを起動できるようになりました。この Codelab の最終的なコードは、GitHub のディレクトリ: Flutter Codelabs

学習した内容

  • Firebase を使用するように Flutter アプリをセットアップする
  • Firebase プロジェクトの設定
  • FlutterFire CLI
  • Firebase CLI
  • Firebase Authentication エミュレータ
  • Firebase Firestore エミュレータ
  • エミュレータ データのインポートとエクスポート

次のステップ

詳細

スパーキーはあなたを誇りに思います。

2a0ad195769368b1.gif