Lokale Entwicklung für Ihre Flutter-Apps mit der Firebase Emulator Suite

1. Bevor Sie beginnen

In diesem Codelab erfahren Sie, wie Sie die Firebase Emulator Suite mit Flutter während der lokalen Entwicklung verwenden. Sie erfahren, wie Sie die E-Mail-Passwort-Authentifizierung über die Emulator Suite verwenden und wie Sie Daten im Firestore-Emulator lesen und schreiben. Schließlich arbeiten Sie mit dem Import und Export von Daten aus den Emulatoren, um bei jeder Rückkehr zur Entwicklung mit denselben gefälschten Daten zu arbeiten.

Voraussetzungen

Dieses Codelab setzt voraus, dass Sie über Flutter-Erfahrung verfügen. Wenn nicht, möchten Sie vielleicht zunächst die Grundlagen erlernen. Die folgenden Links sind hilfreich:

Sie sollten auch über etwas Firebase-Erfahrung verfügen, aber es ist in Ordnung, wenn Sie Firebase noch nie zu einem Flutter-Projekt hinzugefügt haben. Wenn Sie mit der Firebase-Konsole nicht vertraut sind oder ganz neu bei Firebase sind, sehen Sie sich zunächst die folgenden Links an:

Was Sie erstellen werden

Dieses Codelab führt Sie durch die Erstellung einer einfachen Journaling-Anwendung. Die Anwendung verfügt über einen Anmeldebildschirm und einen Bildschirm, auf dem Sie frühere Journaleinträge lesen und neue erstellen können.

cd5c4753bbee8af.png8cb4d21f656540bf.png

Was Sie lernen werden

Sie erfahren, wie Sie mit der Verwendung von Firebase beginnen und wie Sie die Firebase-Emulator-Suite in Ihren Flutter-Entwicklungsworkflow integrieren und verwenden. Diese Firebase-Themen werden behandelt:

Beachten Sie, dass diese Themen insoweit behandelt werden, als sie für die Abdeckung der Firebase-Emulator-Suite erforderlich sind. Dieses Codelab konzentriert sich auf das Hinzufügen eines Firebase-Projekts zu Ihrer Flutter-App und die Entwicklung mit der Firebase Emulator Suite. Es wird keine ausführlichen Diskussionen zu Firebase Authentication oder Firestore geben. Wenn Sie mit diesen Themen nicht vertraut sind, empfehlen wir Ihnen, mit dem Codelab „Firebase für Flutter kennenlernen“ zu beginnen.

Was du brauchen wirst

  • Kenntnisse in Flutter und installiertem SDK
  • Intellij JetBrains- oder VS Code-Texteditoren
  • Google Chrome-Browser (oder Ihr anderes bevorzugtes Entwicklungsziel für Flutter. Einige Terminalbefehle in diesem Codelab gehen davon aus, dass Sie Ihre App auf Chrome ausführen)

2. Erstellen und richten Sie ein Firebase-Projekt ein

Die erste Aufgabe, die Sie erledigen müssen, ist die Erstellung eines Firebase-Projekts in der Webkonsole von Firebase. Ein Großteil dieses Codelabs wird sich auf die Emulator Suite konzentrieren, die eine lokal ausgeführte Benutzeroberfläche verwendet, aber Sie müssen zuerst ein vollständiges Firebase-Projekt einrichten.

Erstellen Sie ein Firebase-Projekt

  1. Melden Sie sich bei der Firebase-Konsole an.
  2. Klicken Sie in der Firebase-Konsole auf Projekt hinzufügen (oder Projekt erstellen ) und geben Sie einen Namen für Ihr Firebase-Projekt ein (z. B. „ Firebase-Flutter-Codelab“) .

fe6aeab3b91965ed.png

  1. Klicken Sie sich durch die Projekterstellungsoptionen. Akzeptieren Sie die Firebase-Bedingungen, wenn Sie dazu aufgefordert werden. Überspringen Sie die Einrichtung von Google Analytics, da Sie Analytics für diese App nicht verwenden werden.

d1fcec48bf251eaa.png

Weitere Informationen zu Firebase-Projekten finden Sie unter Grundlegendes zu Firebase-Projekten .

Die von Ihnen erstellte App verwendet zwei Firebase-Produkte, die für Flutter-Apps verfügbar sind:

  • Firebase-Authentifizierung , damit sich Ihre Benutzer bei Ihrer App anmelden können.
  • Cloud Firestore , um strukturierte Daten in der Cloud zu speichern und sofortige Benachrichtigungen zu erhalten, wenn sich Daten ändern.

Diese beiden Produkte erfordern eine spezielle Konfiguration oder müssen über die Firebase-Konsole aktiviert werden.

Aktivieren Sie Cloud Firestore

Die Flutter-App verwendet Cloud Firestore zum Speichern von Journaleinträgen.

Cloud Firestore aktivieren:

  1. Klicken Sie im Build- Bereich der Firebase-Konsole auf Cloud Firestore .
  2. Klicken Sie auf Datenbank erstellen . 99e8429832d23fa3.png
  3. Wählen Sie die Option Im Testmodus starten . Lesen Sie den Haftungsausschluss zu den Sicherheitsregeln. Der Testmodus stellt sicher, dass Sie während der Entwicklung frei in die Datenbank schreiben können. Weiter klicken . 6be00e26c72ea032.png
  4. Wählen Sie den Speicherort für Ihre Datenbank aus (Sie können einfach die Standardeinstellung verwenden). Beachten Sie, dass dieser Speicherort später nicht geändert werden kann. 278656eefcfb0216.png
  5. Klicken Sie auf Aktivieren .

3. Richten Sie die Flutter-App ein

Bevor wir beginnen, müssen Sie den Startercode herunterladen und die Firebase-CLI installieren.

Holen Sie sich den Startercode

Klonen Sie das GitHub-Repository über die Befehlszeile:

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

Alternativ, wenn Sie das CLI-Tool von GitHub installiert haben:

gh repo clone flutter/codelabs flutter-codelabs

Der Beispielcode sollte in das Verzeichnis flutter-codelabs geklont werden, das den Code für eine Sammlung von Codelabs enthält. Der Code für dieses Codelab befindet sich in flutter-codelabs/firebase-emulator-suite .

Die Verzeichnisstruktur unter flutter-codelabs/firebase-emulator-suite besteht aus zwei Flutter-Projekten. Eine davon heißt complete und Sie können darauf verweisen, wenn Sie weitermachen oder Ihren eigenen Code mit Querverweisen versehen möchten. Das andere Projekt heißt start .

Der Code, mit dem Sie beginnen möchten, befindet sich im Verzeichnis flutter-codelabs/firebase-emulator-suite/start . Öffnen oder importieren Sie dieses Verzeichnis in Ihre bevorzugte IDE.

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

Installieren Sie die Firebase-CLI

Die Firebase-CLI bietet Tools zum Verwalten Ihrer Firebase-Projekte. Für die Verwendung der Emulator Suite ist die CLI erforderlich, daher müssen Sie sie installieren.

Es gibt verschiedene Möglichkeiten, die CLI zu installieren. Wenn Sie MacOS oder Linux verwenden, ist es am einfachsten, diesen Befehl von Ihrem Terminal aus auszuführen:

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

Nach der Installation der CLI müssen Sie sich bei Firebase authentifizieren.

  1. Melden Sie sich mit Ihrem Google-Konto bei Firebase an, indem Sie den folgenden Befehl ausführen:
firebase login
  1. Dieser Befehl verbindet Ihren lokalen Computer mit Firebase und gewährt Ihnen Zugriff auf Ihre Firebase-Projekte.
  1. Testen Sie, ob die CLI ordnungsgemäß installiert ist und Zugriff auf Ihr Konto hat, indem Sie Ihre Firebase-Projekte auflisten. Führen Sie den folgenden Befehl aus:
firebase projects:list
  1. Die angezeigte Liste sollte mit den in der Firebase-Konsole aufgeführten Firebase-Projekten übereinstimmen. Sie sollten mindestens Firebase-flutter-codelab sehen.

Installieren Sie die FlutterFire-CLI

Die FlutterFire-CLI basiert auf der Firebase-CLI und erleichtert die Integration eines Firebase-Projekts in Ihre Flutter-App.

Installieren Sie zunächst die CLI:

dart pub global activate flutterfire_cli

Stellen Sie sicher, dass die CLI installiert wurde. Führen Sie den folgenden Befehl im Flutter-Projektverzeichnis aus und stellen Sie sicher, dass die CLI das Hilfemenü ausgibt.

flutterfire --help

Verwenden Sie Firebase CLI und FlutterFire CLI, um Ihr Firebase-Projekt zu Ihrer Flutter-App hinzuzufügen

Wenn die beiden CLIs installiert sind, können Sie mit nur wenigen Terminalbefehlen einzelne Firebase-Produkte (wie Firestore) einrichten, die Emulatoren herunterladen und Firebase zu Ihrer Flutter-App hinzufügen.

Schließen Sie zunächst die Einrichtung von Firebase ab, indem Sie Folgendes ausführen:

firebase init

Dieser Befehl führt Sie durch eine Reihe von Fragen, die zum Einrichten Ihres Projekts erforderlich sind. Diese Screenshots zeigen den Ablauf:

  1. Wenn Sie aufgefordert werden, Funktionen auszuwählen, wählen Sie „Firestore“ und „Emulatoren“. (Es gibt keine Authentifizierungsoption, da keine Konfiguration verwendet wird, die aus Ihren Flutter-Projektdateien geändert werden kann.) fe6401d769be8f53.png
  2. Wählen Sie als Nächstes „Vorhandenes Projekt verwenden“ aus, wenn Sie dazu aufgefordert werden.

f11dcab439e6ac1e.png

  1. Wählen Sie nun das Projekt aus, das Sie in einem vorherigen Schritt erstellt haben: flutter-firebase-codelab.

3bdc0c6934991c25.png

  1. Als Nächstes werden Ihnen eine Reihe von Fragen zur Benennung der zu generierenden Dateien gestellt. Ich schlage vor, bei jeder Frage die Eingabetaste zu drücken, um den Standardwert auszuwählen. 9bfa2d507e199c59.png
  2. Abschließend müssen Sie die Emulatoren konfigurieren. Wählen Sie Firestore und Authentifizierung aus der Liste aus und drücken Sie dann bei jeder Frage zu den spezifischen Ports, die für jeden Emulator verwendet werden sollen, die Eingabetaste. Sie sollten die Standardeinstellung „Ja“ auswählen, wenn Sie gefragt werden, ob Sie die Emulator-Benutzeroberfläche verwenden möchten.

Am Ende des Vorgangs sollten Sie eine Ausgabe sehen, die wie im folgenden Screenshot aussieht.

Wichtig : Ihre Ausgabe unterscheidet sich möglicherweise geringfügig von meiner, wie im Screenshot unten zu sehen ist, da die letzte Frage standardmäßig „Nein“ lautet, wenn Sie die Emulatoren bereits heruntergeladen haben.

8544e41037637b07.png

Konfigurieren Sie FlutterFire

Als Nächstes können Sie FlutterFire verwenden, um den erforderlichen Dart-Code für die Verwendung von Firebase in Ihrer Flutter-App zu generieren.

flutterfire configure

Wenn dieser Befehl ausgeführt wird, werden Sie aufgefordert, auszuwählen, welches Firebase-Projekt Sie verwenden möchten und welche Plattformen Sie einrichten möchten. In diesem Codelab verwenden die Beispiele Flutter Web, Sie können Ihr Firebase-Projekt jedoch so einrichten, dass alle Optionen verwendet werden.

Die folgenden Screenshots zeigen die Eingabeaufforderungen, die Sie beantworten müssen.

619b7aca6dc15472.png301c9534f594f472.png

Dieser Screenshot zeigt die Ausgabe am Ende des Prozesses. Wenn Sie mit Firebase vertraut sind, werden Sie feststellen, dass Sie keine Anwendungen in der Konsole erstellen mussten und die FlutterFire-CLI dies für Sie erledigt hat.

12199a85ade30459.png

Fügen Sie Firebase-Pakete zur Flutter-App hinzu

Der letzte Einrichtungsschritt besteht darin, die relevanten Firebase-Pakete zu Ihrem Flutter-Projekt hinzuzufügen. Stellen Sie im Terminal sicher, dass Sie sich im Stammverzeichnis des Flutter-Projekts unter flutter-codelabs/firebase-emulator-suite/start befinden. Führen Sie dann die drei folgenden Befehle aus:

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

Dies sind die einzigen Pakete, die Sie in dieser Anwendung verwenden.

4. Firebase-Emulatoren aktivieren

Bisher sind die Flutter-App und Ihr Firebase-Projekt für die Verwendung der Emulatoren eingerichtet, Sie müssen dem Flutter-Code jedoch noch mitteilen, dass er ausgehende Firebase-Anfragen an die lokalen Ports umleiten soll.

Fügen Sie zunächst den Firebase-Initialisierungscode und den Emulator-Setup-Code zur main in main.dart.

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());
}

Die ersten Codezeilen initialisieren Firebase. Wenn Sie mit Firebase in einer Flutter-App arbeiten, sollten Sie fast immer mit dem Aufruf von WidgetsFlutterBinding.ensureInitialized und Firebase.initializeApp beginnen.

Anschließend weist der Code, der mit der Zeile if (kDebugMode) beginnt, Ihre App an, auf die Emulatoren und nicht auf ein Firebase-Produktionsprojekt abzuzielen. kDebugMode stellt sicher, dass die Ausrichtung auf die Emulatoren nur dann erfolgt, wenn Sie sich in einer Entwicklungsumgebung befinden. Da kDebugMode ein konstanter Wert ist, weiß der Dart-Compiler, dass er diesen Codeblock im Release-Modus vollständig entfernen muss.

Starten Sie die Emulatoren

Sie sollten die Emulatoren starten, bevor Sie die Flutter-App starten. Starten Sie zunächst die Emulatoren, indem Sie Folgendes im Terminal ausführen:

firebase emulators:start

Dieser Befehl startet die Emulatoren und stellt Localhost-Ports bereit, über die wir mit ihnen interagieren können. Wenn Sie diesen Befehl ausführen, sollten Sie eine Ausgabe ähnlich dieser sehen:

bb7181eb70829606.png

Diese Ausgabe zeigt Ihnen, welche Emulatoren ausgeführt werden und wo Sie die Emulatoren sehen können. Schauen Sie sich zunächst die Benutzeroberfläche des Emulators unter localhost:4000 an.

11563f4c7216de81.png

Dies ist die Homepage für die Benutzeroberfläche des lokalen Emulators. Es listet alle verfügbaren Emulatoren auf und jeder einzelne ist mit dem Status „Ein“ oder „Aus“ gekennzeichnet.

5. Der Firebase Auth-Emulator

Der erste Emulator, den Sie verwenden, ist der Authentifizierungsemulator. Beginnen Sie mit dem Auth-Emulator, indem Sie auf der Authentifizierungskarte in der Benutzeroberfläche auf „Zum Emulator gehen“ klicken. Daraufhin wird eine Seite angezeigt, die wie folgt aussieht:

3c1bfded40733189.png

Diese Seite weist Ähnlichkeiten mit der Seite der Auth-Webkonsole auf. Es verfügt über eine Tabelle, in der die Benutzer wie in der Online-Konsole aufgeführt sind, und ermöglicht das manuelle Hinzufügen von Benutzern. Ein großer Unterschied besteht darin, dass die einzige auf den Emulatoren verfügbare Authentifizierungsmethode die Verwendung von E-Mail und Passwort ist. Dies reicht für die lokale Entwicklung aus.

Als Nächstes werden Sie durch den Prozess des Hinzufügens eines Benutzers zum Firebase Auth-Emulator und der anschließenden Anmeldung dieses Benutzers über die Flutter-Benutzeroberfläche geführt.

Fügen Sie einen Benutzer hinzu

Klicken Sie auf die Schaltfläche „Benutzer hinzufügen“ und füllen Sie das Formular mit diesen Informationen aus:

  • Anzeigename: Dash
  • E-Mail: dash@email.com
  • Passwort: Strichwort

Senden Sie das Formular ab und Sie werden sehen, dass die Tabelle jetzt einen Benutzer enthält. Jetzt können Sie den Code aktualisieren, um sich mit diesem Benutzer anzumelden.

login_out_view.dart

Der einzige Code im LoggedOutView -Widget, der aktualisiert werden muss, ist der Rückruf, der ausgelöst wird, wenn ein Benutzer die Anmeldeschaltfläche drückt. Aktualisieren Sie den Code so, dass er wie folgt aussieht:

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'),
          ),
        ),
      ],
    ),
   ),
  );
 }
}

Der aktualisierte Code ersetzt die TODO Strings durch die E-Mail-Adresse und das Passwort, die Sie im Authentifizierungsemulator erstellt haben. Und in der nächsten Zeile wurde die if(true) -Zeile durch Code ersetzt, der prüft, ob state.user null ist. Der Code in AppClass bringt mehr Licht ins Dunkel.

app_state.dart

Zwei Teile des Codes in AppState müssen aktualisiert werden. Geben Sie dem Klassenmitglied AppState.user zunächst den Typ User aus dem Paket firebase_auth und nicht den Typ Object .

Zweitens füllen Sie die AppState.login Methode wie unten gezeigt aus:

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!');
   }
 } 
 // ...
}

Die Typdefinition für Benutzer lautet jetzt User? . Diese User Klasse stammt von Firebase Auth und stellt benötigte Informationen wie User.displayName bereit, die gleich besprochen werden.

Dies ist der grundlegende Code, der benötigt wird, um einen Benutzer mit einer E-Mail-Adresse und einem Passwort in Firebase Auth anzumelden. Zur Anmeldung wird FirebaseAuth aufgerufen, wodurch ein Future<UserCredential> -Objekt zurückgegeben wird. Wenn die Zukunft abgeschlossen ist, prüft dieser Code, ob ein User an UserCredential angehängt ist. Wenn das Anmeldeinformationsobjekt einen Benutzer enthält, hat sich ein Benutzer erfolgreich angemeldet und die AppState.user Eigenschaft kann festgelegt werden. Ist dies nicht der Fall, liegt ein Fehler vor und die Meldung wird gedruckt.

Beachten Sie, dass die einzige Codezeile in dieser Methode, die spezifisch für diese App ist (und nicht der allgemeine FirebaseAuth-Code), der Aufruf der _listenForEntries Methode ist, der im nächsten Schritt behandelt wird.

TODO: Aktionssymbol – Laden Sie Ihre App neu und klicken Sie beim Rendern auf die Schaltfläche „Anmelden“. Dadurch navigiert die App zu einer Seite mit der Aufschrift „Willkommen zurück, Person!“ oben. Die Authentifizierung muss funktionieren, da Sie damit zu dieser Seite navigieren können. Es muss jedoch eine geringfügige Aktualisierung an logged_in_view.dart vorgenommen werden, um den tatsächlichen Namen des Benutzers anzuzeigen.

login_in_view.dart

Ändern Sie die erste Zeile in der LoggedInView.build -Methode:

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(
 // ...

Diese Zeile ruft nun den displayName aus der User Eigenschaft des AppState Objekts ab. Dieser displayName wurde im Emulator festgelegt, als Sie Ihren ersten Benutzer definiert haben. Ihre App sollte jetzt „Willkommen zurück, Dash!“ anzeigen. wenn Sie sich anmelden, und nicht TODO .

6. Lesen und Schreiben von Daten in den Firestore-Emulator

Schauen Sie sich zunächst den Firestore-Emulator an. Klicken Sie auf der Startseite der Emulator-Benutzeroberfläche ( localhost:4000 ) auf der Firestore-Karte auf „Zum Emulator gehen“. Es sollte so aussehen:

Emulator:

791fce7dc137910a.png

Firebase-Konsole:

e0dde9aea34af050.png

Wenn Sie Erfahrung mit Firestore haben, werden Sie feststellen, dass diese Seite der Firestore-Seite der Firebase-Konsole ähnelt. Es gibt jedoch einige bemerkenswerte Unterschiede.

  1. Sie können alle Daten mit einem Tastendruck löschen. Dies wäre bei Produktionsdaten gefährlich, ist aber für eine schnelle Iteration hilfreich! Wenn Sie an einem neuen Projekt arbeiten und sich Ihr Datenmodell ändert, ist das leicht zu bereinigen.
  2. Es gibt einen Reiter „Anfragen“. Auf dieser Registerkarte können Sie eingehende Anfragen an diesen Emulator überwachen. Ich werde diese Registerkarte gleich ausführlicher besprechen.
  3. Es gibt keine Registerkarten für Regeln, Indizes oder Verwendung. Es gibt ein Tool (wird im nächsten Abschnitt besprochen), das beim Schreiben von Sicherheitsregeln hilft, Sie können jedoch keine Sicherheitsregeln für den lokalen Emulator festlegen.

Um diese Liste zusammenzufassen: Diese Version von Firestore bietet mehr Tools, die während der Entwicklung nützlich sind, und entfernt Tools, die in der Produktion benötigt werden.

Schreiben Sie an Firestore

Bevor Sie die Registerkarte „Anfragen“ im Emulator besprechen, stellen Sie zunächst eine Anfrage. Dies erfordert Code-Updates. Beginnen Sie damit, das Formular in der App zu verknüpfen, um einen neuen Entry in Firestore zu schreiben.

Der allgemeine Ablauf zum Einreichen eines Entry ist:

  1. Der Benutzer füllt das Formular aus und klickt auf die Schaltfläche Submit .
  2. Die Benutzeroberfläche ruft AppState.writeEntryToFirebase auf
  3. AppState.writeEntryToFirebase fügt Firebase einen Eintrag hinzu

Der in Schritt 1 oder 2 enthaltene Code muss nicht geändert werden. Der einzige Code, der für Schritt 3 hinzugefügt werden muss, wird in der AppState Klasse hinzugefügt. Nehmen Sie die folgende Änderung an AppState.writeEntryToFirebase vor.

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,
   });
 }
 // ...
}

Der Code in der writeEntryToFirebase-Methode ruft einen Verweis auf die Sammlung namens „Entries“ in Firestore ab. Anschließend wird ein neuer Eintrag hinzugefügt, der vom Typ Map<String, String> sein muss.

In diesem Fall war die Sammlung „Einträge“ in Firestore nicht vorhanden, daher hat Firestore eine erstellt.

Nachdem Sie diesen Code hinzugefügt haben, laden Sie Ihre App im laufenden Betrieb neu oder starten Sie sie neu, melden Sie sich an und navigieren Sie zur EntryForm Ansicht. Sie können das Formular mit beliebigen Strings ausfüllen. (Das Datumsfeld nimmt einen beliebigen String an, da es für dieses Codelab vereinfacht wurde. Es verfügt nicht über eine starke Validierung und kümmert sich in keiner Weise um DateTime Objekte.)

Klicken Sie im Formular auf „Senden“. In der App passiert nichts, aber Sie können Ihren neuen Eintrag in der Benutzeroberfläche des Emulators sehen.

Die Registerkarte „Anfragen“ im Firestore-Emulator

Navigieren Sie in der Benutzeroberfläche zum Firestore-Emulator und sehen Sie sich die Registerkarte „Daten“ an. Sie sollten sehen, dass sich jetzt im Stammverzeichnis Ihrer Datenbank eine Sammlung mit dem Namen „Entries“ befindet. Das Dokument sollte die gleichen Informationen enthalten, die Sie in das Formular eingegeben haben.

a978fb34fb8a83da.png

Dies bestätigt, dass AppState.writeEntryToFirestore funktioniert hat, und jetzt können Sie die Anfrage auf der Registerkarte „Anfragen“ weiter untersuchen. Klicken Sie jetzt auf diese Registerkarte.

Anfragen zum Firestore-Emulator

Hier sollten Sie eine Liste sehen, die etwa so aussieht:

f0b37f0341639035.png

Sie können auf jedes dieser Listenelemente klicken und viele hilfreiche Informationen sehen. Klicken Sie auf den Listeneintrag CREATE , der Ihrer Anfrage zum Erstellen eines neuen Journaleintrags entspricht. Sie sehen eine neue Tabelle, die so aussieht:

385d62152e99aad4.png

Wie bereits erwähnt, bietet der Firestore-Emulator Tools zum Entwickeln der Sicherheitsregeln Ihrer App. Diese Ansicht zeigt genau, welche Zeile in Ihren Sicherheitsregeln diese Anfrage bestanden hat (oder fehlgeschlagen ist, falls dies der Fall war). In einer robusteren App können die Sicherheitsregeln wachsen und mehrere Autorisierungsprüfungen umfassen. Diese Ansicht wird zum Schreiben und Debuggen dieser Autorisierungsregeln verwendet.

Es bietet außerdem eine einfache Möglichkeit, jeden Teil dieser Anfrage zu überprüfen, einschließlich der Metadaten und der Authentifizierungsdaten. Diese Daten werden zum Schreiben komplexer Autorisierungsregeln verwendet.

Lesung aus Firestore

Firestore nutzt die Datensynchronisierung, um aktualisierte Daten an verbundene Geräte zu übertragen. Im Flutter-Code können Sie Firestore-Sammlungen und -Dokumente anhören (oder abonnieren) und Ihr Code wird bei jeder Datenänderung benachrichtigt. In dieser App erfolgt die Überwachung auf Firestore-Updates in der Methode AppState._listenForEntries .

Dieser Code funktioniert in Verbindung mit StreamController und Stream namens AppState._entriesStreamController bzw. AppState.entries . Dieser Code ist bereits geschrieben, ebenso wie der gesamte Code, der in der Benutzeroberfläche zum Anzeigen der Daten aus Firestore erforderlich ist.

Aktualisieren Sie die _listenForEntries -Methode so, dass sie mit dem folgenden Code übereinstimmt:

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);
   });
 }
 // ...
}

Dieser Code überwacht die Sammlung „Entries“ im Firestore. Wenn Firestore diesen Client benachrichtigt, dass neue Daten vorliegen, übergibt er diese Daten und der Code in _listenForEntries ändert alle seine untergeordneten Dokumente in ein Objekt, das unsere App verwenden kann ( Entry ). Anschließend werden diese Einträge dem StreamController namens _entriesStreamController hinzugefügt (auf den die Benutzeroberfläche lauscht). Dieser Code ist das einzige erforderliche Update.

Denken Sie abschließend daran, dass die AppState.logIn Methode einen Aufruf an _listenForEntries durchführt, der den Abhörvorgang startet, nachdem sich ein Benutzer angemeldet hat.

// ...
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!');
 }
}
// ...

Führen Sie nun die App aus. Es sollte so aussehen:

b8a31c7a8900331.gif

7. Daten in den Emulator exportieren und importieren

Firebase-Emulatoren unterstützen den Import und Export von Daten. Mithilfe der Importe und Exporte können Sie die Entwicklung mit denselben Daten fortsetzen, wenn Sie eine Entwicklungspause einlegen und dann fortfahren. Sie können Datendateien auch an Git übergeben, und andere Entwickler, mit denen Sie zusammenarbeiten, können mit denselben Daten arbeiten.

Emulatordaten exportieren

Exportieren Sie zunächst die bereits vorhandenen Emulatordaten. Während die Emulatoren noch laufen, öffnen Sie ein neues Terminalfenster und geben Sie den folgenden Befehl ein:

firebase emulators:export ./emulators_data

.emulators_data ist ein Argument, das Firebase mitteilt, wohin die Daten exportiert werden sollen. Wenn das Verzeichnis nicht existiert, wird es erstellt. Sie können für dieses Verzeichnis einen beliebigen Namen verwenden.

Wenn Sie diesen Befehl ausführen, sehen Sie diese Ausgabe in dem Terminal, in dem Sie den Befehl ausgeführt haben:

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

Und wenn Sie zum Terminalfenster wechseln, in dem die Emulatoren ausgeführt werden, sehen Sie diese Ausgabe:

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

Und schließlich, wenn Sie in Ihrem Projektverzeichnis nachsehen, sollten Sie ein Verzeichnis namens ./emulators_data sehen, das neben anderen Metadatendateien JSON Dateien mit den von Ihnen gespeicherten Daten enthält.

Emulatordaten importieren

Jetzt können Sie diese Daten als Teil Ihres Entwicklungsworkflows importieren und dort beginnen, wo Sie aufgehört haben.

Stoppen Sie zunächst die Emulatoren, wenn sie ausgeführt werden, indem Sie in Ihrem Terminal CTRL+C drücken.

Führen Sie als Nächstes den Befehl emulators:start , den Sie bereits gesehen haben, jedoch mit einer Markierung, die angibt, welche Daten importiert werden sollen:

firebase emulators:start --import ./emulators_data

Wenn die Emulatoren aktiv sind, navigieren Sie zur Emulator-Benutzeroberfläche unter localhost:4000 . Dort sollten dieselben Daten angezeigt werden, mit denen Sie zuvor gearbeitet haben.

Exportieren Sie Daten automatisch, wenn Sie Emulatoren schließen

Sie können Daten auch automatisch exportieren, wenn Sie die Emulatoren beenden, anstatt am Ende jeder Entwicklungssitzung daran zu denken, die Daten zu exportieren.

Wenn Sie Ihre Emulatoren starten, führen Sie den Befehl emulators:start mit zwei zusätzlichen Flags aus.

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

Voila! Ihre Daten werden nun gespeichert und jedes Mal neu geladen, wenn Sie mit den Emulatoren für dieses Projekt arbeiten. Sie können auch ein anderes Verzeichnis als Argument für das –export-on-exit flag angeben, es wird jedoch standardmäßig das an –import übergebene Verzeichnis verwendet.

Sie können auch jede beliebige Kombination dieser Optionen verwenden. Dies ist der Hinweis aus den Dokumenten : Das Exportverzeichnis kann mit diesem Flag angegeben werden: firebase emulators:start --export-on-exit=./saved-data . Wenn --import verwendet wird, ist der Exportpfad standardmäßig derselbe; zum Beispiel: firebase emulators:start --import=./data-path --export-on-exit . Übergeben Sie schließlich, falls gewünscht, unterschiedliche Verzeichnispfade an die Flags --import und --export-on-exit .

8. Herzlichen Glückwunsch!

Sie haben die Inbetriebnahme des Firebase-Emulators und Flutter abgeschlossen. Den fertigen Code für dieses Codelab finden Sie im Verzeichnis „complete“ auf Github: Flutter Codelabs

Was wir abgedeckt haben

  • Einrichten einer Flutter-App zur Verwendung von Firebase
  • Einrichten eines Firebase-Projekts
  • FlutterFire-CLI
  • Firebase-CLI
  • Firebase-Authentifizierungsemulator
  • Firebase Firestore-Emulator
  • Emulatordaten importieren und exportieren

Nächste Schritte

Erfahren Sie mehr

Sparky ist stolz auf dich!

2a0ad195769368b1.gif