Développement local pour vos applications Flutter à l'aide de la suite d'émulateurs Firebase

1. Avant de commencer

Dans cet atelier de programmation, vous allez apprendre à utiliser la suite d'émulateurs Firebase avec Flutter lors du développement local. Vous allez apprendre à utiliser l'authentification par adresse e-mail et mot de passe via la suite d'émulateurs, et à lire et écrire des données dans l'émulateur Firestore. Enfin, vous allez importer et exporter des données à partir des émulateurs pour utiliser les mêmes données fictives à chaque fois que vous revenez au développement.

Prérequis

Cet atelier de programmation suppose que vous avez une certaine expérience de Flutter. Dans le cas contraire, vous devriez d'abord vous familiariser avec ses principes de base. Les liens suivants proposent des informations utiles :

Vous devez également avoir une certaine expérience avec Firebase, mais ce n'est pas grave si vous n'avez jamais ajouté Firebase à un projet Flutter. Si vous ne connaissez pas la console Firebase, ou si vous ne connaissez pas la solution, consultez d'abord les liens suivants:

Ce que vous allez créer

Cet atelier de programmation vous explique comment créer une application de journalisation simple. L'application comporte un écran de connexion et un écran qui vous permet de lire les anciennes entrées de journal et d'en créer de nouvelles.

cd5c4753bbee8af.png 8cb4d21f656540bf.png

Points abordés

Vous allez apprendre à utiliser Firebase, et à intégrer et à utiliser la suite d'émulateurs Firebase dans votre workflow de développement Flutter. Voici les thèmes Firebase abordés:

Notez que ces sujets sont abordés dans la mesure où ils sont nécessaires pour couvrir la suite d'émulateurs Firebase. Cet atelier de programmation porte sur l'ajout d'un projet Firebase à votre application Flutter et le développement à l'aide de la suite d'émulateurs Firebase. Il n'y aura pas de discussion approfondie sur Firebase Authentication ni sur Firestore. Si vous ne connaissez pas ces sujets, nous vous recommandons de commencer par l'atelier de programmation Découvrez Firebase pour Flutter.

Prérequis

  • Connaissances pratiques de Flutter et du SDK installé
  • Éditeurs de texte Intellij JetBrains ou VS Code
  • Navigateur Google Chrome (ou autre cible de développement de votre choix pour Flutter). Certaines commandes de terminal de cet atelier de programmation supposent que vous exécutez votre application sur Chrome.

2. Créer et configurer un projet Firebase

La première tâche que vous devez accomplir consiste à créer un projet Firebase dans la console Web de Firebase. La majeure partie de cet atelier de programmation se concentrera sur la suite d'émulateurs, qui utilise une UI exécutée localement, mais vous devez d'abord configurer un projet Firebase complet.

Créer un projet Firebase

  1. Connectez-vous à la console Firebase.
  2. Dans la console Firebase, cliquez sur Ajouter un projet (ou Créer un projet), puis donnez un nom à votre projet Firebase (par exemple, Firebase-Flutter-Codelab).

fe6aeab3b91965ed.png

  1. Cliquez sur les options de création de projet. Si vous y êtes invité, acceptez les conditions d'utilisation de Firebase. Passez l'étape de configuration d'Analytics (vous n'en aurez pas besoin pour cette application).

d1fcec48bf251eaa.png

Pour en savoir plus sur les projets Firebase, consultez Comprendre les projets Firebase.

L'application que vous créez utilise deux produits Firebase disponibles pour les applications Flutter:

  • Firebase Authentication pour permettre à vos utilisateurs de se connecter à votre application
  • Cloud Firestore, pour enregistrer des données structurées dans le cloud et recevoir une notification instantanée en cas de modification des données.

Ces deux produits nécessitent une configuration particulière ou doivent être activés via la console Firebase.

Activer Cloud Firestore

L'application Flutter utilise Cloud Firestore pour enregistrer les entrées de journal.

Activez Cloud Firestore:

  1. Dans la section Build (Créer) de la console Firebase, cliquez sur Cloud Firestore.
  2. Cliquez sur Créer une base de données. 99e8429832d23fa3.png
  3. Sélectionnez l'option Start in test mode (Démarrer en mode test). Lisez la clause de non-responsabilité concernant les règles de sécurité. Le mode test vous permet d'écrire librement dans la base de données pendant le développement. Cliquez sur Suivant. 6be00e26c72ea032.png
  4. Sélectionnez l'emplacement de la base de données (vous pouvez utiliser celui par défaut). Notez toutefois que vous ne pourrez pas en changer par la suite. 278656eefcfb0216.png
  5. Cliquez sur Activer.

3. Configurer l'application Flutter

Avant de commencer, vous devez télécharger le code de démarrage et installer la CLI Firebase.

Télécharger le code de démarrage

Clonez le dépôt GitHub à partir de la ligne de commande :

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

Si vous avez installé l'outil CLI de GitHub:

gh repo clone flutter/codelabs flutter-codelabs

L'exemple de code doit être cloné dans le répertoire flutter-codelabs, qui contient le code d'une collection d'ateliers de programmation. Le code de cet atelier de programmation se trouve dans flutter-codelabs/firebase-emulator-suite.

La structure de répertoires sous flutter-codelabs/firebase-emulator-suite se compose de deux projets Flutter. L'une d'elles s'appelle complete. Vous pouvez vous y référer si vous souhaitez passer à l'étape suivante ou faire des recoupements avec votre propre code. L'autre projet s'appelle start.

Le code avec lequel vous souhaitez commencer se trouve dans le répertoire flutter-codelabs/firebase-emulator-suite/start. Ouvrez ou importez ce répertoire dans l'IDE de votre choix.

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

Installer la CLI Firebase

La CLI Firebase fournit des outils pour gérer vos projets Firebase. La CLI est nécessaire pour utiliser la suite d'émulateurs. Vous devez donc l'installer.

Il existe plusieurs façons d'installer la CLI. Le moyen le plus simple, si vous utilisez macOS ou Linux, consiste à exécuter cette commande à partir de votre terminal:

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

Après avoir installé la CLI, vous devez vous authentifier auprès de Firebase.

  1. Exécutez la commande suivante pour vous connecter à Firebase avec votre compte Google :
firebase login
  1. Cette commande connecte votre machine locale à Firebase et vous permet d'accéder à vos projets Firebase.
  1. Vérifiez que la CLI est correctement installée et qu'elle a accès à votre compte en listant vos projets Firebase. Exécutez la commande suivante :
firebase projects:list
  1. La liste affichée doit être identique à celle des projets Firebase répertoriés dans la console Firebase. Vous devriez y trouver au moins "firebase-flutter-codelab".

Installer la CLI FlutterFire

La CLI FlutterFire est basée sur la CLI Firebase. Elle facilite l'intégration d'un projet Firebase à votre application Flutter.

Commencez par installer la CLI:

dart pub global activate flutterfire_cli

Vérifiez que la CLI a été installée. Exécutez la commande suivante dans le répertoire du projet Flutter et assurez-vous que la CLI affiche le menu d'aide.

flutterfire --help

Utiliser les CLI Firebase et FlutterFire pour ajouter votre projet Firebase à votre application Flutter

Une fois les deux CLI installées, vous pouvez configurer des produits Firebase individuels (comme Firestore), télécharger les émulateurs et ajouter Firebase à votre application Flutter en quelques commandes de terminal.

Commencez par terminer la configuration de Firebase en exécutant la commande suivante:

firebase init

Cette commande vous guidera à travers une série de questions nécessaires à la configuration de votre projet. Ces captures d'écran illustrent le flux:

  1. Lorsque vous êtes invité à sélectionner des fonctionnalités, sélectionnez "Firestore" et "Émulateurs". (Il n'existe pas d'option "Authentification", car elle n'utilise pas de configuration modifiable à partir des fichiers de votre projet Flutter.) fe6401d769be8f53.png
  2. Sélectionnez ensuite "Utiliser un projet existant" lorsque vous y êtes invité.

f11dcab439e6ac1e.png

  1. Sélectionnez maintenant le projet que vous avez créé à l'étape précédente: flutter-firebase-codelab.

3bdc0c6934991c25.png

  1. Vous devrez ensuite répondre à une série de questions sur le nom des fichiers qui seront générés. Je vous suggère d'appuyer sur Entrée pour chaque question afin de sélectionner la valeur par défaut. 9bfa2d507e199c59.png
  2. Enfin, vous devez configurer les émulateurs. Sélectionnez Firestore et Authentication dans la liste, puis appuyez sur "Entrée" pour chaque question concernant les ports spécifiques à utiliser pour chaque émulateur. Vous devez sélectionner la valeur par défaut, "Oui", lorsque vous êtes invité à utiliser l'UI de l'émulateur.

À la fin du processus, vous devriez obtenir un résultat semblable à la capture d'écran suivante.

Important: Votre résultat peut être légèrement différent du mien, comme le montre la capture d'écran ci-dessous, car la dernière question sera définie par défaut sur "No" si vous avez déjà téléchargé les émulateurs.

8544e41037637b07.png

Configurer FlutterFire

Vous pouvez ensuite utiliser FlutterFire pour générer le code Dart nécessaire à l'utilisation de Firebase dans votre application Flutter.

flutterfire configure

Lorsque vous exécutez cette commande, vous êtes invité à sélectionner le projet Firebase que vous souhaitez utiliser et les plates-formes que vous souhaitez configurer. Dans cet atelier de programmation, les exemples utilisent Flutter Web, mais vous pouvez configurer votre projet Firebase pour utiliser toutes les options.

Les captures d'écran suivantes montrent les requêtes auxquelles vous devrez répondre.

619b7aca6dc15472.png 301c9534f594f472.png

Cette capture d'écran montre le résultat à la fin du processus. Si vous connaissez Firebase, vous remarquerez que vous n'avez pas eu à créer d'applications dans la console. La CLI FlutterFire s'en est chargée.

12199a85ade30459.png

Ajouter des packages Firebase à l'application Flutter

La dernière étape de configuration consiste à ajouter les packages Firebase pertinents à votre projet Flutter. Dans le terminal, vérifiez que vous vous trouvez à la racine du projet Flutter, sous flutter-codelabs/firebase-emulator-suite/start. Exécutez ensuite les trois commandes suivantes:

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

Ce sont les seuls packages que vous utiliserez dans cette application.

4. Activer les émulateurs Firebase

Jusqu'à présent, l'application Flutter et votre projet Firebase sont configurés pour pouvoir utiliser les émulateurs, mais vous devez toujours indiquer au code Flutter de rediriger les requêtes Firebase sortantes vers les ports locaux.

Commencez par ajouter le code d'initialisation Firebase et le code de configuration de l'émulateur à la fonction main dans 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());
}

Les premières lignes de code initialisent Firebase. Presque systématiquement, si vous travaillez avec Firebase dans une application Flutter, vous devez commencer par appeler WidgetsFlutterBinding.ensureInitialized et Firebase.initializeApp.

Ensuite, le code commençant par la ligne if (kDebugMode) indique à votre application de cibler les émulateurs plutôt qu'un projet Firebase de production. kDebugMode garantit que le ciblage des émulateurs ne se produit que si vous vous trouvez dans un environnement de développement. Étant donné que kDebugMode est une valeur constante, le compilateur Dart sait supprimer complètement ce bloc de code en mode version.

Démarrer les émulateurs

Vous devez démarrer les émulateurs avant de démarrer l'application Flutter. Commencez par démarrer les émulateurs en exécutant ce code dans le terminal:

firebase emulators:start

Cette commande démarre les émulateurs et révèle les ports localhost avec lesquels nous pouvons interagir. Lorsque vous exécutez cette commande, vous devriez obtenir un résultat semblable à celui-ci:

bb7181eb70829606.png

Ce résultat indique les émulateurs en cours d'exécution et l'emplacement où vous pouvez les consulter. Commencez par consulter l'interface utilisateur de l'émulateur à l'adresse localhost:4000.

11563f4c7216de81.png

Il s'agit de la page d'accueil de l'interface utilisateur de l'émulateur local. Il répertorie tous les émulateurs disponibles, et chacun d'eux est associé à un état activé ou désactivé.

5. L'émulateur Firebase Auth

Le premier émulateur que vous allez utiliser est l'émulateur d'authentification. Commencez par l'émulateur Auth en cliquant sur "Accéder à l'émulateur" sur la fiche "Authentification" dans l'UI. Une page semblable à celle-ci s'affiche:

3c1bfded40733189.png

Cette page présente des similitudes avec la page d'authentification de la console Web. Elle comporte un tableau qui liste les utilisateurs, comme dans la console en ligne, et vous permet d'en ajouter manuellement. La principale différence est que la seule méthode d'authentification disponible sur les émulateurs est l'e-mail et le mot de passe. C'est suffisant pour le développement local.

Vous allez ensuite découvrir comment ajouter un utilisateur à l'émulateur Firebase Auth, puis le connecter via l'UI Flutter.

Ajouter un utilisateur

Cliquez sur le bouton "Ajouter un utilisateur" et remplissez le formulaire avec les informations suivantes:

  • Nom à afficher: Dash
  • Adresse e-mail: dash@email.com
  • Mot de passe: dashword

Envoyez le formulaire. Vous verrez que le tableau inclut désormais un utilisateur. Vous pouvez maintenant modifier le code pour vous connecter avec cet utilisateur.

logged_out_view.dart

Le seul code du widget LoggedOutView qui doit être mis à jour se trouve dans le rappel qui est déclenché lorsqu'un utilisateur appuie sur le bouton de connexion. Remplacez le code par le code suivant:

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

Le code mis à jour remplace les chaînes TODO par l'adresse e-mail et le mot de passe que vous avez créés dans l'émulateur auth. Dans la ligne suivante, la ligne if(true) a été remplacée par un code qui vérifie si state.user est nul. Le code de AppClass apporte plus de précisions à ce sujet.

app_state.dart

Deux parties du code dans AppState doivent être mises à jour. Tout d'abord, attribuez au membre de la classe AppState.user le type User à partir du package firebase_auth, plutôt que le type Object.

Ensuite, renseignez la méthode AppState.login comme indiqué ci-dessous:

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

La définition de type pour l'utilisateur est désormais User?. Cette classe User provient d'Authentification Firebase et fournit les informations nécessaires, telles que User.displayName, qui sera abordée plus tard.

Il s'agit du code de base nécessaire pour connecter un utilisateur avec une adresse e-mail et un mot de passe dans Firebase Authentication. Il appelle FirebaseAuth pour se connecter, ce qui renvoie un objet Future<UserCredential>. Une fois le futur terminé, ce code vérifie si un User est associé au UserCredential. Si un utilisateur est présent dans l'objet d'identifiants, cela signifie qu'un utilisateur s'est connecté et que la propriété AppState.user peut être définie. Si ce n'est pas le cas, une erreur s'est produite et elle est imprimée.

Notez que la seule ligne de code de cette méthode qui est spécifique à cette application (plutôt qu'au code FirebaseAuth général) est l'appel de la méthode _listenForEntries, qui sera abordé à l'étape suivante.

À FAIRE : Icône d'action : actualisez votre application, puis appuyez sur le bouton de connexion lorsqu'il s'affiche. L'application redirige alors l'utilisateur vers une page qui affiche le message "Bienvenue, Personne !" en haut. L'authentification doit fonctionner, car elle vous a permis d'accéder à cette page. Toutefois, une mise à jour mineure doit être apportée à logged_in_view.dart pour afficher le nom réel de l'utilisateur.

logged_in_view.dart

Modifiez la première ligne de la méthode 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(
 // ...

Cette ligne récupère maintenant le displayName à partir de la propriété User de l'objet AppState. Ce displayName a été défini dans l'émulateur lorsque vous avez défini votre premier utilisateur. Votre application devrait désormais afficher "Bienvenue, Dash !" lorsque vous vous connectez, au lieu de TODO.

6. Lire et écrire des données dans l'émulateur Firestore

Commencez par consulter l'émulateur Firestore. Sur la page d'accueil de l'interface utilisateur de l'émulateur (localhost:4000), cliquez sur "Accéder à l'émulateur" dans la fiche Firestore. Elle devrait se présenter comme ceci :

Émulateur:

791fce7dc137910a.png

Console Firebase:

e0dde9aea34af050.png

Si vous avez de l'expérience avec Firestore, vous remarquerez que cette page ressemble à la page Firestore de la console Firebase. Il existe toutefois quelques différences notables.

  1. Vous pouvez effacer toutes les données en appuyant sur un bouton. Cela serait dangereux avec des données de production, mais cela permet d'effectuer des itérations rapides. Si vous travaillez sur un nouveau projet et que votre modèle de données change, vous pouvez facilement le supprimer.
  2. Vous y trouverez un onglet "Demandes". Cet onglet vous permet de surveiller les requêtes entrantes envoyées à cet émulateur. Je reviendrai sur cet onglet plus en détail dans un instant.
  3. Il n'y a pas d'onglets pour les règles, les index ni l'utilisation. Un outil (décrit dans la section suivante) vous aide à écrire des règles de sécurité, mais vous ne pouvez pas définir de règles de sécurité pour l'émulateur local.

Pour résumer cette liste, cette version de Firestore offre des outils supplémentaires utiles pendant le développement et supprime ceux qui sont nécessaires en production.

Écrire dans Firestore

Avant de consulter l'onglet "Demandes" dans l'émulateur, faites une demande. Cela nécessite des mises à jour de code. Commencez par connecter le formulaire dans l'application pour écrire un journal Entry dans Firestore.

Voici le flux général pour envoyer une Entry:

  1. L'utilisateur remplit le formulaire et appuie sur le bouton Submit
  2. L'UI appelle AppState.writeEntryToFirebase
  3. AppState.writeEntryToFirebase ajoute une entrée à Firebase

Aucun code impliqué dans les étapes 1 ou 2 ne doit être modifié. Le seul code à ajouter pour l'étape 3 sera ajouté dans la classe AppState. Apportez la modification suivante à 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,
   });
 }
 // ...
}

Le code de la méthode writeEntryToFirebase récupère une référence à la collection appelée "Entries" (Entrées) dans Firestore. Il ajoute ensuite une nouvelle entrée, qui doit être de type Map<String, String>.

Dans ce cas, la collection "Entries" (Enregistrements) de Firestore n'existait pas. Firestore en a donc créé une.

Une fois ce code ajouté, effectuez un hot reload ou un redémarrage à chaud de votre application, connectez-vous et accédez à la vue EntryForm. Vous pouvez remplir le formulaire avec l'Strings de votre choix. (Le champ "Date" accepte n'importe quelle chaîne, car il a été simplifié pour cet atelier de programmation. Il n'effectue pas de validation stricte et ne se soucie pas des objets DateTime.)

Appuyez sur "Envoyer" dans le formulaire. Rien ne se passe dans l'application, mais vous pouvez voir votre nouvelle entrée dans l'interface utilisateur de l'émulateur.

Onglet "Requêtes" de l'émulateur Firestore

Dans l'UI, accédez à l'émulateur Firestore, puis examinez l'onglet "Données". Une collection appelée "Entries " (Enregistrements) devrait s'afficher à la racine de votre base de données. Vous devriez y trouver un document contenant les mêmes informations que celles que vous avez saisies dans le formulaire.

a978fb34fb8a83da.png

Cela confirme que l'AppState.writeEntryToFirestore a fonctionné. Vous pouvez maintenant examiner plus en détail la requête dans l'onglet "Requêtes". Cliquez sur cet onglet.

Requêtes de l'émulateur Firestore

Une liste semblable à celle-ci devrait s'afficher:

f0b37f0341639035.png

Vous pouvez cliquer sur n'importe lequel de ces éléments pour afficher de nombreuses informations utiles. Cliquez sur l'élément de liste CREATE correspondant à votre demande pour créer une entrée de journal. Un nouveau tableau s'affiche:

385d62152e99aad4.png

Comme indiqué, l'émulateur Firestore fournit des outils pour développer les règles de sécurité de votre application. Cette vue indique exactement quelle ligne de vos règles de sécurité cette requête a respectée (ou non, le cas échéant). Dans une application plus robuste, les règles de sécurité peuvent croître et comporter plusieurs vérifications d'autorisation. Cette vue permet d'écrire et de déboguer ces règles d'autorisation.

Il permet également d'inspecter facilement chaque élément de cette requête, y compris les métadonnées et les données d'authentification. Ces données sont utilisées pour écrire des règles d'autorisation complexes.

Lire à partir de Firestore

Firestore utilise la synchronisation des données pour transmettre les données mises à jour aux appareils connectés. Dans le code Flutter, vous pouvez écouter (ou vous abonner) aux collections et documents Firestore, et votre code sera averti à chaque modification des données. Dans cette application, l'écoute des mises à jour Firestore est effectuée dans la méthode appelée AppState._listenForEntries.

Ce code fonctionne conjointement avec les StreamController et Stream appelés AppState._entriesStreamController et AppState.entries, respectivement. Ce code est déjà écrit, de même que tout le code nécessaire à l'interface utilisateur pour afficher les données de Firestore.

Mettez à jour la méthode _listenForEntries pour qu'elle corresponde au code ci-dessous:

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

Ce code écoute la collection "Entries" (Entrées) dans Firestore. Lorsque Firestore informe ce client de la présence de nouvelles données, il les transmet, et le code de _listenForEntries transforme tous ses documents enfants en un objet que notre application peut utiliser (Entry). Il ajoute ensuite ces entrées à la StreamController appelée _entriesStreamController (que l'UI écoute). Ce code est la seule mise à jour requise.

Enfin, n'oubliez pas que la méthode AppState.logIn appelle _listenForEntries, qui lance le processus d'écoute une fois qu'un utilisateur s'est connecté.

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

Exécutez l'application. Elle devrait se présenter comme suit:

b8a31c7a8900331.gif

7. Exporter et importer des données dans l'émulateur

Les émulateurs Firebase sont compatibles avec l'importation et l'exportation de données. Les importations et exportations vous permettent de continuer le développement avec les mêmes données lorsque vous faites une pause, puis de reprendre. Vous pouvez également valider des fichiers de données dans Git. Les autres développeurs avec lesquels vous travaillez auront alors accès aux mêmes données.

Exporter les données de l'émulateur

Commencez par exporter les données de l'émulateur que vous possédez déjà. Pendant que les émulateurs sont en cours d'exécution, ouvrez une nouvelle fenêtre de terminal et saisissez la commande suivante:

firebase emulators:export ./emulators_data

.emulators_data est un argument qui indique à Firebase où exporter les données. Si le répertoire n'existe pas, il est créé. Vous pouvez utiliser le nom de votre choix pour ce répertoire.

Lorsque vous exécutez cette commande, le résultat suivant s'affiche dans le terminal:

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

Si vous passez à la fenêtre de terminal dans laquelle les émulateurs s'exécutent, vous obtiendrez le résultat suivant:

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

Enfin, si vous examinez le répertoire de votre projet, vous devriez voir un répertoire nommé ./emulators_data, qui contient des fichiers JSON, entre autres fichiers de métadonnées, avec les données que vous avez enregistrées.

Importer des données de l'émulateur

Vous pouvez maintenant importer ces données dans le cadre de votre workflow de développement et reprendre là où vous vous étiez arrêté.

Commencez par arrêter les émulateurs s'ils sont en cours d'exécution en appuyant sur CTRL+C dans le terminal.

Exécutez ensuite la commande emulators:start que vous avez déjà vue, mais avec un indicateur indiquant les données à importer:

firebase emulators:start --import ./emulators_data

Une fois les émulateurs démarrés, accédez à l'interface utilisateur de l'émulateur à l'adresse localhost:4000. Vous devriez voir les mêmes données que celles que vous utilisiez auparavant.

Exporter automatiquement les données lorsque vous fermez des émulateurs

Vous pouvez également exporter les données automatiquement lorsque vous quittez les émulateurs, au lieu de penser à les exporter à la fin de chaque session de développement.

Lorsque vous démarrez vos émulateurs, exécutez la commande emulators:start avec deux options supplémentaires.

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

Voilà ! Vos données seront désormais enregistrées et réactivées chaque fois que vous utiliserez les émulateurs pour ce projet. Vous pouvez également spécifier un autre répertoire en tant qu'argument de –export-on-exit flag, mais le répertoire transmis à –import sera utilisé par défaut.

Vous pouvez également combiner ces options. Voici la remarque de la documentation : Le répertoire d'exportation peut être spécifié avec l'option firebase emulators:start --export-on-exit=./saved-data. Si --import est utilisé, le chemin d'exportation est le même par défaut (par exemple, firebase emulators:start --import=./data-path --export-on-exit). Enfin, si vous le souhaitez, transmettez différents chemins d'accès aux indicateurs --import et --export-on-exit.

8. Félicitations !

Vous avez terminé la section "Premiers pas avec l'émulateur Firebase et Flutter". Le code final de cet atelier de programmation est disponible dans le répertoire "complete" de GitHub: Flutter Codelabs.

Points abordés

  • Configurer une application Flutter pour utiliser Firebase
  • Configurer un projet Firebase
  • CLI FlutterFire
  • CLI Firebase
  • Émulateur Firebase Authentication
  • Émulateur Firebase Firestore
  • Importer et exporter des données de l'émulateur

Étapes suivantes

En savoir plus

Sparky est fier de vous !

2a0ad195769368b1.gif