Découvrez Firebase pour Flutter

1. Avant de commencer

Dans ce codelab, vous apprendrez quelques - unes des bases de Firebase pour créer des applications mobiles Flutter pour Android et iOS.

Conditions préalables

Ce codelab suppose que vous connaissez avec Flutter, et que vous avez installé le SDK Flutter , et un éditeur .

Ce que vous allez créer

Dans cet atelier de programmation, vous allez créer une application de discussion RSVP et de livre d'or sur Android, iOS, le Web et macOS à l'aide de Flutter. Vous authentifierez les utilisateurs avec Firebase Authentication et synchroniserez les données à l'aide de Cloud Firestore.

Ce dont vous aurez besoin

Vous pouvez exécuter cet atelier de programmation à l'aide de l'un des appareils suivants :

  • Un appareil physique (Android ou iOS) connecté à votre ordinateur et réglé en mode développeur.
  • Le simulateur iOS. (Nécessite l' installation d' outils Xcode .)
  • L'émulateur Android. (Nécessite l' installation dans Android studio .)

En plus de ce qui précède, vous aurez également besoin de :

  • Un navigateur de votre choix, tel que Chrome.
  • Un IDE ou un éditeur de texte de votre choix, comme Android studio ou code VS configuré avec les plugins Dart et Flutter.
  • La dernière stable version de Flutter (ou beta si vous aimez vivre sur le bord).
  • Un compte Google, comme un compte Gmail, pour créer et gérer votre projet Firebase.
  • L'exemple de code du laboratoire de programmation. Voir l'étape suivante pour savoir comment obtenir le code.

2. Obtenez l'exemple de code

Commençons par télécharger la version initiale de notre projet depuis GitHub.

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

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

Sinon, si vous avez cli de GitHub outil installé:

gh repo clone flutter/codelabs flutter-codelabs

L'exemple de code doit être cloné dans le flutter-codelabs répertoire, qui contient le code pour une collection de codelabs. Le code de cette codelab est en flutter-codelabs/firebase-get-to-know-flutter .

La structure de répertoire sous flutter-codelabs/firebase-get-to-know-flutter est une série de clichés de l' endroit où vous devriez être à la fin de chaque étape du nom. Il s'agit de l'étape 2, donc localiser les fichiers correspondants est aussi simple que :

cd flutter-codelabs/firebase-get-to-know-flutter/step_02

Si vous voulez avancer ou voir à quoi devrait ressembler quelque chose après une étape, regardez dans le répertoire nommé d'après l'étape qui vous intéresse.

Importer l'application de démarrage

Ouvrir ou importer les flutter-codelabs/firebase-get-to-know-flutter/step_02 répertoire dans votre IDE préféré. Ce répertoire contient le code de démarrage du laboratoire de programmation qui consiste en une application de rencontre Flutter qui n'est pas encore fonctionnelle.

Localisez les fichiers sur lesquels travailler

Le code de cette application est réparti sur plusieurs répertoires. Cette répartition des fonctionnalités est conçue pour faciliter le travail, en regroupant le code par fonctionnalité.

Recherchez les fichiers suivants dans le projet :

  • lib/main.dart : Ce fichier contient le principal point d'entrée et le widget de l' application.
  • lib/src/widgets.dart : Ce fichier contient une poignée de widgets pour standardiser le style de l'application. Ceux-ci sont utilisés pour composer l'écran de l'application de démarrage.
  • lib/src/authentication.dart : Ce fichier contient une mise en œuvre partielle de FirebaseUI Auth avec un ensemble de widgets pour créer une connexion expérience utilisateur pour l' authentification par e - mail Firebase. Ces widgets pour le flux d'authentification ne sont pas encore utilisés dans l'application de démarrage, mais vous les connecterez bientôt.

Vous ajouterez des fichiers supplémentaires au besoin pour créer le reste de l'application.

Examen de la lib/main.dart fichier

Cette application profite du google_fonts ensemble pour nous permettre de faire Roboto la police par défaut tout au long de l'application entière. Un exercice pour le lecteur motivé est d'explorer fonts.google.com et utiliser les polices que vous découvrirez dans les différentes parties de l'application.

Vous êtes en utilisant les widgets d'aide de lib/src/widgets.dart sous la forme d' en- Header , le Paragraph et IconAndDetail . Ces widgets réduisent l' encombrement dans la mise en page décrit dans HomePage en éliminant le code dupliquée. Cela a l'avantage supplémentaire de permettre une apparence et une sensation cohérentes.

Voici à quoi ressemble votre application sur Android, iOS, le Web et macOS :

Aperçu de l'application

3. Créer et configurer un projet Firebase

L'affichage des informations sur l'événement est excellent pour vos invités, mais le simple fait de montrer les événements n'est très utile pour personne. Ajoutons des fonctionnalités dynamiques à cette application. Pour cela, vous devrez connecter Firebase à votre application. Pour commencer avec Firebase, vous devez créer et configurer un projet Firebase.

Créer un projet Firebase

  1. Se connecter à Firebase .
  2. Dans la console Firebase, cliquez sur Ajouter un projet (ou Créer un projet) et nommez votre projet Firebase Firebase-Flutter-Codelab.

4395e4e67c08043a.png

  1. Cliquez sur les options de création de projet. Acceptez les conditions de Firebase si vous y êtes invité. Ignorez la configuration de Google Analytics, car vous n'utiliserez pas Analytics pour cette application.

b7138cde5f2c7b61.png

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

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

  • Firebase authentification pour permettre à vos utilisateurs de se connecter à votre application.
  • Cloud Firestore pour enregistrer des données structurées sur le nuage et la notification instantanée obtenir des modifications de données.
  • Règles de sécurité Firebase pour sécuriser votre base de données.

Certains de ces produits nécessitent une configuration spéciale ou doivent être activés à l'aide de la console Firebase.

Activer email de connexion pour l' authentification Firebase

Pour permettre aux utilisateurs de se connecter à l'application Web, vous utiliserez la page de connexion Email / Mot de passe pour cette méthode codelab:

  1. Dans la console Firebase, développez le menu Générer dans le panneau de gauche.
  2. Cliquez sur Authentification, puis cliquez sur le bouton Commencer, l'inscription dans l' onglet méthode (ou cliquez ici pour aller directement à l'inscription dans l' onglet méthode).
  3. Cliquez sur Courriel / mot de passe dans la liste d' inscription dans les fournisseurs, réglez l'interrupteur d' activation à la position, puis cliquez sur Enregistrer. 58e3e3e23c2f16a4.png

Activer Cloud Firestore

L'application Web utilise - Cloud Firestore pour enregistrer des messages de chat et recevoir de nouveaux messages de chat.

Activez Cloud Firestore :

  1. Dans la section de construction de la console Firebase, cliquez sur Nuage Firestore.
  2. Cliquez sur Créer la base de données. 99e8429832d23fa3.png
  1. Sélectionnez Démarrer en option en mode test. Lisez la clause de non-responsabilité concernant les règles de sécurité. Le mode test garantit que vous pouvez librement écrire dans la base de données pendant le développement. Cliquez sur Suivant. 6be00e26c72ea032.png
  1. Sélectionnez l'emplacement de votre base de données (vous pouvez simplement utiliser la valeur par défaut). Notez que cet emplacement ne peut pas être modifié ultérieurement. 278656eefcfb0216.png
  2. Cliquez sur Activer.

4. Configuration de la base de feu

Pour utiliser Firebase avec Flutter, vous devez suivre un processus pour configurer le projet Flutter afin d'utiliser correctement les bibliothèques FlutterFire :

  • Ajoutez les dépendances FlutterFire à votre projet
  • Enregistrez la plate-forme souhaitée sur le projet Firebase
  • Téléchargez le fichier de configuration spécifique à la plate-forme et ajoutez-le au code.

Dans le répertoire de niveau supérieur de votre application Flutter, il y a des sous - répertoires appelés ios et android . Ces répertoires contiennent respectivement les fichiers de configuration spécifiques à la plate-forme pour iOS et Android.

Configurer les dépendances

Vous devez ajouter les bibliothèques FlutterFire pour les deux produits Firebase que vous utilisez dans cette application - Firebase Auth et Cloud Firestore. Exécutez les trois commandes suivantes pour ajouter les dépendances.

$ flutter pub add firebase_core
Resolving dependencies...
  async 2.8.1 (2.8.2 available)
+ firebase_core 1.6.0
+ firebase_core_platform_interface 4.0.1
+ firebase_core_web 1.1.0
+ flutter_web_plugins 0.0.0 from sdk flutter
+ js 0.6.3
  matcher 0.12.10 (0.12.11 available)
  path_provider 2.0.2 (2.0.3 available)
  platform 3.0.0 (3.0.2 available)
  test_api 0.4.2 (0.4.3 available)
  win32 2.2.5 (2.2.9 available)
Changed 5 dependencies!

Le firebase_core est le code commun requis pour tous les plug - ins Firebase Flutter.

$ flutter pub add firebase_auth
Resolving dependencies...
  async 2.8.1 (2.8.2 available)
+ firebase_auth 3.1.0
+ firebase_auth_platform_interface 6.1.0
+ firebase_auth_web 3.1.0
+ intl 0.17.0
  matcher 0.12.10 (0.12.11 available)
  path_provider 2.0.2 (2.0.3 available)
  platform 3.0.0 (3.0.2 available)
  test_api 0.4.2 (0.4.3 available)
  win32 2.2.5 (2.2.9 available)
Changed 4 dependencies!

Le firebase_auth permet l' intégration avec la capacité d' authentification de Firebase.

$ flutter pub add cloud_firestore
Resolving dependencies...
  async 2.8.1 (2.8.2 available)
+ cloud_firestore 2.5.1
+ cloud_firestore_platform_interface 5.4.1
+ cloud_firestore_web 2.4.1
  matcher 0.12.10 (0.12.11 available)
  path_provider 2.0.2 (2.0.3 available)
  platform 3.0.0 (3.0.2 available)
  test_api 0.4.2 (0.4.3 available)
  win32 2.2.5 (2.2.9 available)
Changed 3 dependencies!

Le cloud_firestore permet l' accès au stockage de données cloud Firestore.

$ flutter pub add provider
Resolving dependencies...
  async 2.8.1 (2.8.2 available)
  matcher 0.12.10 (0.12.11 available)
+ nested 1.0.0
  path_provider 2.0.2 (2.0.3 available)
  platform 3.0.0 (3.0.2 available)
+ provider 6.0.0
  test_api 0.4.2 (0.4.3 available)
  win32 2.2.5 (2.2.9 available)
Changed 2 dependencies!

Bien que vous ayez ajouté les packages requis, vous devez également configurer les projets iOS, Android, macOS et Web runner pour utiliser correctement Firebase. Vous utilisez également le provider package qui permettra la séparation de la logique métier de la logique d'affichage.

Configurer iOS

  1. Dans la console Firebase , sélectionnez Aperçu du projet dans la barre de navigation de gauche, puis cliquez sur le bouton iOS sous Commencez par ajouter Firebase à votre application.

Vous devriez voir la boîte de dialogue suivante :

c42139f18fb9a2ee.png

  1. La valeur importante est de fournir l'ID de paquet iOS. Vous obtenez l'ID du bundle en effectuant les trois étapes suivantes.
  1. Dans l'outil de ligne de commande, accédez au répertoire de niveau supérieur de votre application Flutter.
  2. Exécutez la commande open ios/Runner.xcworkspace pour ouvrir Xcode.
  1. Dans Xcode, cliquez sur le haut niveau Runner dans le volet gauche, puis sélectionnez Runner sous Cibles, pour montrer l'onglet Général dans le volet de droite, comme indiqué. Copiez la valeur Identificateur Bundle.

9d67acd88c718763.png

  1. Retour à la boîte de dialogue Firebase, collez le copié Bundle Identifier dans le champ d'ID de paquet iOS et cliquez sur Enregistrer App.
  1. En continuant à Firebase, suivez les instructions pour télécharger le fichier de configuration GoogleService-Info.plist .
  2. Retournez à Xcode. Notez que coureur a un sous - répertoire appelé aussi coureur (montré dans l'image précédente).
  3. Faites glisser le GoogleService-Info.plist fichier (que vous venez de télécharger) dans ce sous - dossier Runner.
  4. Dans la boîte de dialogue qui apparaît dans Xcode, cliquez sur Terminer.
  5. N'hésitez pas à fermer Xcode à ce stade, car ce n'est pas nécessaire à l'avenir.
  6. Revenez à la console Firebase. Dans l'étape de configuration, cliquez sur Suivant, sauter les étapes restantes, et revenir à la page principale de la console Firebase.

Vous avez terminé de configurer votre application Flutter pour iOS. Pour plus de détails, voir s'il vous plaît la documentation d'installation FlutterFire iOS .

Configurer Android

  1. Dans la console Firebase , sélectionnez Aperçu du projet dans la barre de navigation de gauche, puis cliquez sur le bouton Android sous Commencez par ajouter Firebase à votre application.

Vous devriez voir la boîte de dialogue suivante : 8254fc299e82f528.png

  1. La valeur est important de fournir le nom de package Android. Vous obtenez le nom du package lorsque vous effectuez les deux étapes suivantes :
  1. Dans votre répertoire d'applications Flutter, ouvrez le fichier android/app/src/main/AndroidManifest.xml .
  2. Dans le manifest élément, trouver la valeur de chaîne du package attribut. Cette valeur est le nom du package Android (quelque chose comme com.yourcompany.yourproject ). Copiez cette valeur.
  3. Dans la boîte de dialogue Firebase, collez le nom du package copié dans le champ Nom du package Android.
  4. Vous n'avez pas besoin du certificat de signature de débogage SHA-1 pour cette codelab. Laissez ce champ vide.
  5. Cliquez sur Enregistrer App.
  6. En continuant à Firebase, suivez les instructions pour télécharger le fichier de configuration google-services.json .
  7. Accédez à votre répertoire d'applications Flutter, et déplacer le google-services.json fichier (que vous venez de télécharger) dans l' android/app répertoire.
  8. De retour dans la console Firebase, ignorez les étapes restantes et revenez à la page principale de la console Firebase.
  9. Modifier votre android/build.gradle pour ajouter les google-services plug - in dépendance:

android/build.gradle

dependencies {
        classpath 'com.android.tools.build:gradle:4.1.0'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath 'com.google.gms:google-services:4.3.5'  // new
}
  1. Modifier votre android/app/build.gradle pour permettre aux google-services plugin:

android/app/build.gradle

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
apply plugin: 'com.google.gms.google-services'  // new
  1. Firebase nécessite que Multidex soit activé, et une façon de le faire est de définir le SDK minimum pris en charge sur 21 ou plus. Modifier votre android/app/build.gradle mise à jour minSdkVersion :

android/app/build.gradle

defaultConfig {
    applicationId "com.example.gtk_flutter"
    minSdkVersion 21  // Updated
    targetSdkVersion 30
    versionCode flutterVersionCode.toInteger()
    versionName flutterVersionName
}

Vous avez terminé de configurer votre application Flutter pour Android. Pour plus de détails, voir s'il vous plaît la documentation d'installation FlutterFire Android .

Configurer pour le Web

  1. Dans la console Firebase , sélectionnez Aperçu du projet dans la barre de navigation de gauche, puis cliquez sur le bouton Web sous Commencez par ajouter Firebase à votre application.

25b14deff9e589ce.png

  1. Donnez cette application un surnom, puis cliquez sur le bouton de l' application de vous inscrire. Nous allons laisser l'hébergement Firebase désactivé pour ce didacticiel, car nous ne l'exécuterons que localement. N'hésitez pas à en savoir plus sur Firebase Hosting ici. 9c697cc1b309c806.png
  2. Modifier la section de corps de votre web/index.html fichier comme suit. Assurez - vous d'ajouter les firebaseConfig données de l'étape précédente.

web/index.html

<body>
  <script>
    if ('serviceWorker' in navigator) {
      window.addEventListener('flutter-first-frame', function () {
        navigator.serviceWorker.register('flutter_service_worker.js');
      });
    }
  </script>

  <!-- Add from here -->
  <script src="https://www.gstatic.com/firebasejs/7.20.0/firebase-app.js"></script>
  <script src="https://www.gstatic.com/firebasejs/7.20.0/firebase-auth.js"></script>
  <script src="https://www.gstatic.com/firebasejs/7.20.0/firebase-firestore.js"></script>
  <script>
    // Your web app's Firebase configuration
    var firebaseConfig = {
      // Replace this with your firebaseConfig
    };
    // Initialize Firebase
    firebase.initializeApp(firebaseConfig);
  </script>
  <!-- to here. -->

  <script src="main.dart.js" type="application/javascript"></script>
</body>

Vous avez terminé de configurer votre application Flutter pour le Web. Pour plus de détails, voir s'il vous plaît la documentation d'installation Web FlutterFire .

Configurer macOS

Les étapes de configuration pour macOS sont presque identiques à iOS. Nous allons fichier de configuration réutilisation GoogleService-Info.plist de l'iOS étapes ci - dessus.

  1. Exécutez la commande open macos/Runner.xcworkspace pour ouvrir Xcode.
  1. Faites glisser le GoogleService-Info.plist fichier dans le sous - dossier Runner. Il a été créé dans les étapes ci - dessus Configurer iOS. c2b9229a605fd738.png
  2. Dans le macos/Runner/DebugProfile.entitlements fichier, ajoutez un com.apple.security.network.client droit, et il réglé sur true . 8bee5665e35d3f34.png
  3. Dans le macos/Runner/Release.entitlements fichier, ajoutez également un com.apple.security.network.client droit, et mis à true . 41e2e23b7928546a.png
  4. N'hésitez pas à fermer Xcode à ce stade, car ce n'est pas nécessaire à l'avenir.

Vous avez terminé de configurer votre application Flutter pour macOS. Pour plus de détails, voir s'il vous plaît la documentation d'installation FlutterFire macOS , et le support Desktop pour Flutter page.

5. Ajouter une connexion utilisateur (RSVP)

Maintenant que vous avez ajouté Firebase à l'application, vous pouvez configurer un bouton RSVP que les gens de registres à l' aide Firebase authentification . Pour Android natif, iOS natif et Web, il existe des packages FirebaseUI Auth pré-construits, mais pour Flutter, vous devrez créer cette capacité.

Le projet que vous avez récupéré à l'étape 2 comprenait un ensemble de widgets qui implémentent l'interface utilisateur pour la plupart du flux d'authentification. Vous implémenterez la logique métier pour intégrer Firebase Authentication dans l'application.

Logique métier avec le fournisseur

Vous allez utiliser le provider package pour faire un objet d'état d'application centralisée disponible dans tout l'arbre des widgets Flutter de l'application. Pour commencer, modifier les importations en haut de lib/main.dart :

lib/main.dart

import 'package:firebase_core/firebase_core.dart'; // new
import 'package:firebase_auth/firebase_auth.dart'; // new
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';           // new

import 'src/authentication.dart';                  // new
import 'src/widgets.dart';

Les import lignes introduisent Firebase de base et Auth, tirez le provider package que vous utilisez pour faire l'application objet d'état disponible dans l'arborescence widget, et comprennent les widgets d'authentification de lib/src .

Cette application objet d'état, ApplicationState , a deux responsabilités principales de cette étape, mais gagnera des responsabilités supplémentaires que vous ajoutez plus de fonctionnalités à l'application dans les étapes ultérieures. La première responsabilité est d'initialiser la bibliothèque Firebase avec un appel à Firebase.initializeApp() , et puis il y a la gestion du flux d'autorisation. Ajoutez la classe suivante à la fin de lib/main.dart :

lib/main.dart

class ApplicationState extends ChangeNotifier {
  ApplicationState() {
    init();
  }

  Future<void> init() async {
    await Firebase.initializeApp();

    FirebaseAuth.instance.userChanges().listen((user) {
      if (user != null) {
        _loginState = ApplicationLoginState.loggedIn;
      } else {
        _loginState = ApplicationLoginState.loggedOut;
      }
      notifyListeners();
    });
  }

  ApplicationLoginState _loginState = ApplicationLoginState.loggedOut;
  ApplicationLoginState get loginState => _loginState;

  String? _email;
  String? get email => _email;

  void startLoginFlow() {
    _loginState = ApplicationLoginState.emailAddress;
    notifyListeners();
  }

  void verifyEmail(
    String email,
    void Function(FirebaseAuthException e) errorCallback,
  ) async {
    try {
      var methods =
          await FirebaseAuth.instance.fetchSignInMethodsForEmail(email);
      if (methods.contains('password')) {
        _loginState = ApplicationLoginState.password;
      } else {
        _loginState = ApplicationLoginState.register;
      }
      _email = email;
      notifyListeners();
    } on FirebaseAuthException catch (e) {
      errorCallback(e);
    }
  }

  void signInWithEmailAndPassword(
    String email,
    String password,
    void Function(FirebaseAuthException e) errorCallback,
  ) async {
    try {
      await FirebaseAuth.instance.signInWithEmailAndPassword(
        email: email,
        password: password,
      );
    } on FirebaseAuthException catch (e) {
      errorCallback(e);
    }
  }

  void cancelRegistration() {
    _loginState = ApplicationLoginState.emailAddress;
    notifyListeners();
  }

  void registerAccount(String email, String displayName, String password,
      void Function(FirebaseAuthException e) errorCallback) async {
    try {
      var credential = await FirebaseAuth.instance
          .createUserWithEmailAndPassword(email: email, password: password);
      await credential.user!.updateProfile(displayName: displayName);
    } on FirebaseAuthException catch (e) {
      errorCallback(e);
    }
  }

  void signOut() {
    FirebaseAuth.instance.signOut();
  }
}

Il convient de noter quelques points clés dans cette classe. L'utilisateur commence sans s'authentifier, l'application affiche un formulaire demandant l'adresse e-mail de l'utilisateur, selon que cette adresse e-mail est dans le fichier, l'application demandera à l'utilisateur de s'inscrire ou de demander son mot de passe, puis en supposant que tout fonctionne, l'utilisateur est authentifié.

Il convient de noter qu'il ne s'agit pas d'une implémentation complète du flux FirebaseUI Auth, car il ne gère pas le cas d'un utilisateur avec un compte existant qui a des difficultés à se connecter. La mise en œuvre de cette capacité supplémentaire est laissée en exercice au lecteur motivé.

Intégration du flux d'authentification

Maintenant que vous avez le début de l'état de l' application , il est temps de câbler l'état d'application dans l'initialisation de l' application et ajouter le flux d'authentification dans HomePage . Mettre à jour le principal point d'entrée pour intégrer l' état d'application via le provider package:

lib/main.dart

void main() {
  // Modify from here
  runApp(
    ChangeNotifierProvider(
      create: (context) => ApplicationState(),
      builder: (context, _) => App(),
    ),
  );
  // to here.
}

La modification de la main fonction rend le package de fournisseur responsable de l' instanciation l'application objet d'état en utilisant le ChangeNotifierProvider widget de . Vous utilisez cette classe de fournisseur spécifique parce que l'objet de l' état d'application étend ChangeNotifier et cela permet au provider package de savoir quand réafficher widgets dépendants. Enfin, intégrer l'état d'application avec l' Authentication par la mise à jour HomePage de » build méthode:

lib/main.dart

class HomePage extends StatelessWidget {
  HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Firebase Meetup'),
      ),
      body: ListView(
        children: <Widget>[
          Image.asset('assets/codelab.png'),
          SizedBox(height: 8),
          IconAndDetail(Icons.calendar_today, 'October 30'),
          IconAndDetail(Icons.location_city, 'San Francisco'),
          // Add from here
          Consumer<ApplicationState>(
            builder: (context, appState, _) => Authentication(
              email: appState.email,
              loginState: appState.loginState,
              startLoginFlow: appState.startLoginFlow,
              verifyEmail: appState.verifyEmail,
              signInWithEmailAndPassword: appState.signInWithEmailAndPassword,
              cancelRegistration: appState.cancelRegistration,
              registerAccount: appState.registerAccount,
              signOut: appState.signOut,
            ),
          ),
          // to here
          Divider(
            height: 8,
            thickness: 1,
            indent: 8,
            endIndent: 8,
            color: Colors.grey,
          ),
          Header("What we'll be doing"),
          Paragraph(
            'Join us for a day full of Firebase Workshops and Pizza!',
          ),
        ],
      ),
    );
  }
}

Vous instancier l' Authentication widget et l' envelopper dans un Consumer un widget. Le consommateur le widget comme d' habitude que le provider package peut être utilisé pour reconstruire une partie de l'arbre lorsque les changements d'état de l' application. L' Authentication widget est l'interface utilisateur d'authentification que vous allez test maintenant.

Test du flux d'authentification

cdf2d25e436bd48d.png

Voici le début du flux d'authentification, où l'utilisateur peut appuyer sur le bouton RSVP pour lancer le formulaire de courrier électronique.

2a2cd6d69d172369.png

Lors de la saisie de l'e-mail, le système confirme si l'utilisateur est déjà enregistré, auquel cas l'utilisateur est invité à saisir un mot de passe, sinon, si l'utilisateur n'est pas enregistré, il passe par le formulaire d'enregistrement.

e5e65065dba36b54.png

Assurez-vous d'essayer d'entrer un mot de passe court (moins de six caractères) pour vérifier le flux de traitement des erreurs. Si l'utilisateur est enregistré, il verra le mot de passe à la place.

fbb3ea35fb4f67a.png

Sur cette page, assurez-vous d'entrer des mots de passe incorrects pour vérifier la gestion des erreurs sur cette page. Enfin, une fois que l'utilisateur est connecté, vous verrez l'expérience de connexion qui offre à l'utilisateur la possibilité de se déconnecter à nouveau.

4ed811a25b0cf816.png

Et avec cela, vous avez mis en place un flux d'authentification. Félicitations!

6. Écrire des messages dans Cloud Firestore

Savoir que les utilisateurs arrivent, c'est bien, mais donnons aux invités autre chose à faire dans l'application. Et s'ils pouvaient laisser des messages dans un livre d'or ? Ils peuvent partager pourquoi ils sont ravis de venir ou qui ils espèrent rencontrer.

Pour enregistrer les messages de chat que les utilisateurs écrivent dans l'application, vous utiliserez - Cloud Firestore .

Modèle de données

Cloud Firestore est une base de données NoSQL, et les données stockées dans la base de données sont divisées en collections, documents, champs et sous-collections. Vous stockerez chaque message de chat comme un document dans une collection de niveau supérieur appelé guestbook d' guestbook .

7c20dc8424bb1d84.png

Ajouter des messages à Firestore

Dans cette section, vous allez ajouter la fonctionnalité permettant aux utilisateurs d'écrire de nouveaux messages dans la base de données. Tout d'abord, vous ajoutez les éléments de l'interface utilisateur (champ de formulaire et bouton d'envoi), puis vous ajoutez le code qui relie ces éléments à la base de données.

Tout d' abord, ajouter les importations pour le cloud_firestore paquet et dart:async .

lib/main.dart

import 'dart:async';                                    // new
import 'package:cloud_firestore/cloud_firestore.dart';  // new
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';

import 'src/authentication.dart';
import 'src/widgets.dart';

Pour construire les éléments de l' interface utilisateur d'un champ de message et un bouton d'envoi, ajouter un nouveau widget de stateful GuestBook au bas de lib/main.dart .

lib/main.dart

class GuestBook extends StatefulWidget {
  GuestBook({required this.addMessage});
  final FutureOr<void> Function(String message) addMessage;

  @override
  _GuestBookState createState() => _GuestBookState();
}

class _GuestBookState extends State<GuestBook> {
  final _formKey = GlobalKey<FormState>(debugLabel: '_GuestBookState');
  final _controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: Form(
        key: _formKey,
        child: Row(
          children: [
            Expanded(
              child: TextFormField(
                controller: _controller,
                decoration: const InputDecoration(
                  hintText: 'Leave a message',
                ),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Enter your message to continue';
                  }
                  return null;
                },
              ),
            ),
            SizedBox(width: 8),
            StyledButton(
              onPressed: () async {
                if (_formKey.currentState!.validate()) {
                  await widget.addMessage(_controller.text);
                  _controller.clear();
                }
              },
              child: Row(
                children: [
                  Icon(Icons.send),
                  SizedBox(width: 4),
                  Text('SEND'),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Il y a quelques points d'intérêt ici. Tout d'abord, vous instanciez un formulaire afin qu'upi puisse valider que le message a réellement du contenu et montrer à l'utilisateur un message d'erreur s'il n'y en a pas. La façon de valider un formulaire implique l' accès à l'état de forme derrière la forme, et pour cela vous utilisez un GlobalKey . Pour plus d' informations sur les clés, et comment les utiliser, s'il vous plaît voir le Flutter Widgets 101 épisode « Quand utiliser les touches » .

Notez également la façon dont les widgets sont disposés, vous avez une Row , avec un TextFormField et un StyledButton , qui contient lui - même une Row . A noter également le TextFormField est enveloppé dans un Expanded widget ces forces du TextFormField de prendre tout l' espace supplémentaire dans la ligne. Pour mieux comprendre pourquoi cela est nécessaire, s'il vous plaît lire par comprendre les contraintes .

Maintenant que vous disposez d'un widget qui permet à l'utilisateur de saisir du texte à ajouter au livre d'or, vous devez l'afficher à l'écran. Pour ce faire, modifier le corps de HomePage pour ajouter au bas de deux lignes suivantes ListView enfants de:

Header("What we'll be doing"),
Paragraph(
  'Join us for a day full of Firebase Workshops and Pizza!',
),
// Add the following two lines.
Header('Discussion'),
GuestBook(addMessage: (String message) => print(message)),

Bien que cela soit suffisant pour afficher le Widget, cela ne suffit pas pour faire quoi que ce soit d'utile. Vous allez mettre à jour ce code sous peu pour le rendre fonctionnel.

Aperçu de l'application

Un utilisateur en cliquant sur le bouton ENVOYER déclenche l'extrait de code ci - dessous. Il ajoute le contenu du champ de saisie de message au guestbook d' guestbook collection de la base de données. Plus précisément, la addMessageToGuestBook méthode ajoute le contenu du message à un nouveau document (avec un ID généré automatiquement) au guestbook d' guestbook collection.

Notez que FirebaseAuth.instance.currentUser.uid est une référence à l'ID unique généré automatiquement que l' authentification Firebase donne pour tous les utilisateurs connectés.

Faire une autre modification du lib/main.dart fichier. Ajouter la addMessageToGuestBook méthode. Vous câblerez l'interface utilisateur et cette capacité ensemble à l'étape suivante.

lib/main.dart

class ApplicationState extends ChangeNotifier {

  // Current content of ApplicationState elided ...

  // Add from here
  Future<DocumentReference> addMessageToGuestBook(String message) {
    if (_loginState != ApplicationLoginState.loggedIn) {
      throw Exception('Must be logged in');
    }

    return FirebaseFirestore.instance.collection('guestbook').add(<String, dynamic>{
      'text': message,
      'timestamp': DateTime.now().millisecondsSinceEpoch,
      'name': FirebaseAuth.instance.currentUser!.displayName,
      'userId': FirebaseAuth.instance.currentUser!.uid,
    });
  }
  // To here
}

Câblage de l'interface utilisateur dans la base de données

Vous disposez d'une interface utilisateur dans laquelle l'utilisateur peut saisir le texte qu'il souhaite ajouter au livre d'or et vous disposez du code pour ajouter l'entrée à Cloud Firestore. Il ne vous reste plus qu'à câbler les deux ensemble. Dans lib/main.dart faire le changement suivant au HomePage un widget.

lib/main.dart

class HomePage extends StatelessWidget {
  HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Firebase Meetup'),
      ),
      body: ListView(
        children: <Widget>[
          Image.asset('assets/codelab.png'),
          SizedBox(height: 8),
          IconAndDetail(Icons.calendar_today, 'October 30'),
          IconAndDetail(Icons.location_city, 'San Francisco'),
          Consumer<ApplicationState>(
            builder: (context, appState, _) => Authentication(
              email: appState.email,
              loginState: appState.loginState,
              startLoginFlow: appState.startLoginFlow,
              verifyEmail: appState.verifyEmail,
              signInWithEmailAndPassword: appState.signInWithEmailAndPassword,
              cancelRegistration: appState.cancelRegistration,
              registerAccount: appState.registerAccount,
              signOut: appState.signOut,
            ),
          ),
          Divider(
            height: 8,
            thickness: 1,
            indent: 8,
            endIndent: 8,
            color: Colors.grey,
          ),
          Header("What we'll be doing"),
          Paragraph(
            'Join us for a day full of Firebase Workshops and Pizza!',
          ),
          // Modify from here
          Consumer<ApplicationState>(
            builder: (context, appState, _) => Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                if (appState.loginState == ApplicationLoginState.loggedIn) ...[
                  Header('Discussion'),
                  GuestBook(
                    addMessage: (String message) =>
                        appState.addMessageToGuestBook(message),
                  ),
                ],
              ],
            ),
          ),
          // To here.
        ],
      ),
    );
  }
}

Vous avez remplacé les deux lignes que vous avez ajoutées au début de cette étape par l'implémentation complète. Vous utilisez à nouveau la Consumer<ApplicationState> pour faire l'état de l' application à la disposition de la partie de l'arbre que vous êtes rendu. Cela vous permet de réagir à la saisie d'un message dans l'interface utilisateur et de le publier dans la base de données. Dans la section suivante, vous testerez si les messages ajoutés sont publiés dans la base de données.

Tester l'envoi de messages

  1. Assurez-vous que vous êtes connecté à l'application.
  2. Entrez un message tel que « Hé! », Puis cliquez sur ENVOYER.

Cette action écrit le message dans votre base de données Cloud Firestore. Cependant, vous ne verrez pas encore le message dans votre application Flutter actuelle, car vous devez toujours implémenter la récupération des données. Vous le ferez à l'étape suivante.

Mais vous pouvez voir le message nouvellement ajouté dans la console Firebase.

Dans la console Firebase, dans le tableau de guestbook bord de base de données , vous devriez voir le guestbook d' guestbook collection avec votre message nouvellement ajouté. Si vous continuez à envoyer des messages, votre collection de livres d'or contiendra de nombreux documents, comme celui-ci :

Console Firebase

713870af0b3b63c.png

7. Lire les messages

C'est bien que les invités puissent écrire des messages dans la base de données, mais ils ne peuvent pas encore les voir dans l'application. Réparons ça !

Synchroniser les messages

Pour afficher les messages, vous devez ajouter des écouteurs qui se déclenchent lorsque les données changent, puis créer un élément d'interface utilisateur qui affiche les nouveaux messages. Vous allez ajouter du code à l'état de l'application qui écoute les messages nouvellement ajoutés de l'application.

Juste au- dessus du GuestBook le widget classe de valeur suivante. Cette classe expose une vue structurée des données que vous stockez dans Cloud Firestore.

lib/main.dart

class GuestBookMessage {
  GuestBookMessage({required this.name, required this.message});
  final String name;
  final String message;
}

Dans la section de ApplicationState où vous définissez l' état et getters, ajoutez les nouvelles lignes suivantes:

lib/main.dart

  ApplicationLoginState _loginState = ApplicationLoginState.loggedOut;
  ApplicationLoginState get loginState => _loginState;

  String? _email;
  String? get email => _email;

  // Add from here
  StreamSubscription<QuerySnapshot>? _guestBookSubscription;
  List<GuestBookMessage> _guestBookMessages = [];
  List<GuestBookMessage> get guestBookMessages => _guestBookMessages;
  // to here.

Enfin, dans la section d'initialisation de ApplicationState , ajoutez ce qui suit pour vous abonner à une requête sur la collection de documents lorsqu'un utilisateur se connecte et désabonnement lorsqu'ils se déconnectent.

lib/main.dart

  Future<void> init() async {
    await Firebase.initializeApp();

    FirebaseAuth.instance.userChanges().listen((user) {
      if (user != null) {
        _loginState = ApplicationLoginState.loggedIn;
        // Add from here
        _guestBookSubscription = FirebaseFirestore.instance
            .collection('guestbook')
            .orderBy('timestamp', descending: true)
            .snapshots()
            .listen((snapshot) {
          _guestBookMessages = [];
          snapshot.docs.forEach((document) {
            _guestBookMessages.add(
              GuestBookMessage(
                name: document.data()['name'],
                message: document.data()['text'],
              ),
            );
          });
          notifyListeners();
        });
        // to here.
      } else {
        _loginState = ApplicationLoginState.loggedOut;
        // Add from here
        _guestBookMessages = [];
        _guestBookSubscription?.cancel();
        // to here.
      }
      notifyListeners();
    });
  }

Cette section est importante, est comme ici où vous construisez une requête sur le guestbook d' guestbook collection et poignée abonnement et désabonnement à cette collection. Vous écoutez le flux, où vous reconstituez un cache local des messages dans le guestbook d' guestbook collection, et stocker également une référence à cet abonnement afin que vous puissiez vous désabonner de plus tard. Il se passe beaucoup de choses ici, et cela vaut la peine de passer du temps dans un débogueur à inspecter ce qui se passe pour obtenir un modèle mental plus clair.

Pour plus d' informations, consultez la documentation Firestore - Cloud .

Dans le GuestBook vous devez connecter le widget que ce changement d' état à l'interface utilisateur. Vous modifiez le widget en ajoutant une liste de messages dans le cadre de sa configuration.

lib/main.dart

class GuestBook extends StatefulWidget {
  // Modify the following line
  GuestBook({required this.addMessage, required this.messages});
  final FutureOr<void> Function(String message) addMessage;
  final List<GuestBookMessage> messages; // new

  @override
  _GuestBookState createState() => _GuestBookState();
}

Ensuite, nous exposons cette nouvelle configuration dans _GuestBookState en modifiant la build méthode comme suit.

lib/main.dart

class _GuestBookState extends State<GuestBook> {
  final _formKey = GlobalKey<FormState>(debugLabel: '_GuestBookState');
  final _controller = TextEditingController();

  @override
  // Modify from here
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        // to here.
        Padding(
          padding: const EdgeInsets.all(8.0),
          child: Form(
            key: _formKey,
            child: Row(
              children: [
                Expanded(
                  child: TextFormField(
                    controller: _controller,
                    decoration: const InputDecoration(
                      hintText: 'Leave a message',
                    ),
                    validator: (value) {
                      if (value == null || value.isEmpty) {
                        return 'Enter your message to continue';
                      }
                      return null;
                    },
                  ),
                ),
                SizedBox(width: 8),
                StyledButton(
                  onPressed: () async {
                    if (_formKey.currentState!.validate()) {
                      await widget.addMessage(_controller.text);
                      _controller.clear();
                    }
                  },
                  child: Row(
                    children: [
                      Icon(Icons.send),
                      SizedBox(width: 4),
                      Text('SEND'),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
        // Modify from here
        SizedBox(height: 8),
        for (var message in widget.messages)
          Paragraph('${message.name}: ${message.message}'),
        SizedBox(height: 8),
        // to here.
      ],
    );
  }
}

Vous enroulez le contenu précédent de la méthode de construction avec une Column widget, puis à la queue de la Column enfants de vous ajoutez une collection pour générer un nouveau Paragraph pour chaque message dans la liste des messages.

Enfin, vous devez maintenant mettre à jour le corps de HomePage pour construire correctement GuestBook avec les nouveaux messages paramètre.

lib/main.dart

Consumer<ApplicationState>(
  builder: (context, appState, _) => Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      if (appState.loginState == ApplicationLoginState.loggedIn) ...[
        Header('Discussion'),
        GuestBook(
          addMessage: (String message) =>
              appState.addMessageToGuestBook(message),
          messages: appState.guestBookMessages, // new
        ),
      ],
    ],
  ),
),

Tester la synchronisation des messages

Cloud Firestore synchronise automatiquement et instantanément les données avec les clients abonnés à la base de données.

  1. Les messages que vous avez créés précédemment dans la base de données doivent être affichés dans l'application. N'hésitez pas à écrire de nouveaux messages ; ils devraient apparaître instantanément.
  2. Si vous ouvrez votre espace de travail dans plusieurs fenêtres ou onglets, les messages seront synchronisés en temps réel entre les onglets.
  3. (Facultatif) Vous pouvez essayer de supprimer manuellement, la modification ou l' ajout de nouveaux messages directement dans la section de base de données de la console Firebase; tout changement devrait apparaître dans l'interface utilisateur.

Toutes nos félicitations! Vous lisez des documents Cloud Firestore dans votre application !

App Review p

8. Mettre en place des règles de sécurité de base

Vous avez initialement configuré Cloud Firestore pour utiliser le mode test, ce qui signifie que votre base de données est ouverte en lecture et en écriture. Cependant, vous ne devez utiliser le mode test qu'au tout début du développement. En tant que meilleure pratique, vous devez définir des règles de sécurité pour votre base de données lors du développement de votre application. La sécurité doit faire partie intégrante de la structure et du comportement de votre application.

Les règles de sécurité vous permettent de contrôler l'accès aux documents et aux collections de votre base de données. La syntaxe flexible des règles vous permet de créer des règles qui correspondent à tout, de toutes les écritures à l'ensemble de la base de données aux opérations sur un document spécifique.

Vous pouvez écrire des règles de sécurité pour Cloud Firestore dans la console Firebase :

  1. Dans la section Développement de la console Firebase, cliquez sur Base de données, puis sélectionnez l'onglet Règles (ou cliquez ici pour accéder directement à l'onglet Règles).
  2. Vous devriez voir les règles de sécurité par défaut suivantes, ainsi qu'un avertissement indiquant que les règles sont publiques.

7767a2d2e64e7275.png

Identifier les collections

Tout d'abord, identifiez les collections dans lesquelles l'application écrit des données.

Dans match /databases/{database}/documents de match /databases/{database}/documents de match /databases/{database}/documents , identifier la collection que vous souhaitez sécuriser:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /guestbook/{entry} {
     // You'll add rules here in the next step.
  }
}

Ajouter des règles de sécurité

Étant donné que vous avez utilisé l'UID d'authentification comme champ dans chaque document de livre d'or, vous pouvez obtenir l'UID d'authentification et vérifier que toute personne tentant d'écrire dans le document possède un UID d'authentification correspondant.

Ajoutez les règles de lecture et d'écriture à votre ensemble de règles, comme indiqué ci-dessous :

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /guestbook/{entry} {
      allow read: if request.auth.uid != null;
      allow write:
        if request.auth.uid == request.resource.data.userId;
    }
  }
}

Désormais, pour le livre d'or, seuls les utilisateurs connectés peuvent lire les messages (n'importe quel message !), mais seul l'auteur d'un message peut modifier un message.

Ajouter des règles de validation

Ajoutez la validation des données pour vous assurer que tous les champs attendus sont présents dans le document :

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /guestbook/{entry} {
      allow read: if request.auth.uid != null;
      allow write:
      if request.auth.uid == request.resource.data.userId
          && "name" in request.resource.data
          && "text" in request.resource.data
          && "timestamp" in request.resource.data;
    }
  }
}

9. Étape bonus : mettez en pratique ce que vous avez appris

Enregistrer le statut RSVP d'un participant

Pour le moment, votre application permet simplement aux gens de commencer à discuter s'ils sont intéressés par l'événement. De plus, la seule façon de savoir si quelqu'un vient est de le publier dans le chat. Organisons-nous et informons les gens du nombre de personnes qui viennent.

Vous allez ajouter quelques nouvelles fonctionnalités à l'état de l'application. Le premier est la possibilité pour un utilisateur connecté de désigner s'il participe ou non. La deuxième capacité est un compteur du nombre de personnes réellement présentes.

Dans lib/main.dart , ajoutez ce qui suit à la section accesseurs pour activer le code de l' interface utilisateur d'interagir avec cet état:

lib/main.dart

int _attendees = 0;
int get attendees => _attendees;

Attending _attending = Attending.unknown;
StreamSubscription<DocumentSnapshot>? _attendingSubscription;
Attending get attending => _attending;
set attending(Attending attending) {
  final userDoc = FirebaseFirestore.instance
      .collection('attendees')
      .doc(FirebaseAuth.instance.currentUser!.uid);
  if (attending == Attending.yes) {
    userDoc.set({'attending': true});
  } else {
    userDoc.set({'attending': false});
  }
}

Mise à jour ApplicationState de init méthode comme suit:

lib/main.dart

  Future<void> init() async {
    await Firebase.initializeApp();

    // Add from here
    FirebaseFirestore.instance
        .collection('attendees')
        .where('attending', isEqualTo: true)
        .snapshots()
        .listen((snapshot) {
      _attendees = snapshot.docs.length;
      notifyListeners();
    });
    // To here

    FirebaseAuth.instance.userChanges().listen((user) {
      if (user != null) {
        _loginState = ApplicationLoginState.loggedIn;
        _guestBookSubscription = FirebaseFirestore.instance
            .collection('guestbook')
            .orderBy('timestamp', descending: true)
            .snapshots()
            .listen((snapshot) {
          _guestBookMessages = [];
          snapshot.docs.forEach((document) {
            _guestBookMessages.add(
              GuestBookMessage(
                name: document.data()['name'],
                message: document.data()['text'],
              ),
            );
          });
          notifyListeners();
        });
        // Add from here
        _attendingSubscription = FirebaseFirestore.instance
            .collection('attendees')
            .doc(user.uid)
            .snapshots()
            .listen((snapshot) {
          if (snapshot.data() != null) {
            if (snapshot.data()!['attending']) {
              _attending = Attending.yes;
            } else {
              _attending = Attending.no;
            }
          } else {
            _attending = Attending.unknown;
          }
          notifyListeners();
        });
        // to here
      } else {
        _loginState = ApplicationLoginState.loggedOut;
        _guestBookMessages = [];
        _guestBookSubscription?.cancel();
        _attendingSubscription?.cancel(); // new
      }
      notifyListeners();
    });
  }

Ce qui précède ajoute une requête toujours abonnée pour connaître le nombre de participants, et une deuxième requête qui n'est active que lorsqu'un utilisateur est connecté pour savoir si l'utilisateur est présent. Ensuite, ajoutez l'énumération suivante après la GuestBookMessage déclaration:

lib/main.dart

enum Attending { yes, no, unknown }

Vous allez maintenant définir un nouveau widget qui agit comme les anciens boutons radio. Il commence dans un état indéterminé, sans oui ni non sélectionné, mais une fois que l'utilisateur choisit s'il participe ou non, vous affichez cette option en surbrillance avec un bouton rempli et l'autre option recule avec un rendu plat.

lib/main.dart

class YesNoSelection extends StatelessWidget {
  const YesNoSelection({required this.state, required this.onSelection});
  final Attending state;
  final void Function(Attending selection) onSelection;

  @override
  Widget build(BuildContext context) {
    switch (state) {
      case Attending.yes:
        return Padding(
          padding: EdgeInsets.all(8.0),
          child: Row(
            children: [
              ElevatedButton(
                style: ElevatedButton.styleFrom(elevation: 0),
                onPressed: () => onSelection(Attending.yes),
                child: Text('YES'),
              ),
              SizedBox(width: 8),
              TextButton(
                onPressed: () => onSelection(Attending.no),
                child: Text('NO'),
              ),
            ],
          ),
        );
      case Attending.no:
        return Padding(
          padding: EdgeInsets.all(8.0),
          child: Row(
            children: [
              TextButton(
                onPressed: () => onSelection(Attending.yes),
                child: Text('YES'),
              ),
              SizedBox(width: 8),
              ElevatedButton(
                style: ElevatedButton.styleFrom(elevation: 0),
                onPressed: () => onSelection(Attending.no),
                child: Text('NO'),
              ),
            ],
          ),
        );
      default:
        return Padding(
          padding: EdgeInsets.all(8.0),
          child: Row(
            children: [
              StyledButton(
                onPressed: () => onSelection(Attending.yes),
                child: Text('YES'),
              ),
              SizedBox(width: 8),
              StyledButton(
                onPressed: () => onSelection(Attending.no),
                child: Text('NO'),
              ),
            ],
          ),
        );
    }
  }
}

Ensuite, vous devez mettre à jour HomePage méthode de construction d » pour tirer profit de YesNoSelection , ce qui permet un utilisateur connecté à nominer si elles participent. Vous afficherez également le nombre de participants à cet événement.

lib/main.dart

Consumer<ApplicationState>(
  builder: (context, appState, _) => Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      // Add from here
      if (appState.attendees >= 2)
        Paragraph('${appState.attendees} people going')
      else if (appState.attendees == 1)
        Paragraph('1 person going')
      else
        Paragraph('No one going'),
      // To here.
      if (appState.loginState == ApplicationLoginState.loggedIn) ...[
        // Add from here
        YesNoSelection(
          state: appState.attending,
          onSelection: (attending) => appState.attending = attending,
        ),
        // To here.
        Header('Discussion'),
        GuestBook(
          addMessage: (String message) =>
              appState.addMessageToGuestBook(message),
          messages: appState.guestBookMessages,
        ),
      ],
    ],
  ),
),

Ajouter des règles

Parce que vous avez déjà configuré certaines règles, les nouvelles données que vous ajoutez avec les boutons vont être rejetées. Vous aurez besoin de mettre à jour les règles pour permettre l' ajout d' au attendees collection.

Pour les attendees collection, depuis que vous avez utilisé l'UID d' authentification comme le nom du document, vous pouvez saisir et vérifier que le demandeur uid est le même que le document qu'ils écrivent. Vous autoriserez tout le monde à lire la liste des participants (puisqu'il n'y a pas de données privées là-bas), mais seul le créateur devrait pouvoir la mettre à jour.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // ... //
    match /attendees/{userId} {
      allow read: if true;
      allow write: if request.auth.uid == userId;
    }
  }
}

Ajouter des règles de validation

Ajoutez la validation des données pour vous assurer que tous les champs attendus sont présents dans le document :

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // ... //
    match /attendees/{userId} {
      allow read: if true;
      allow write: if request.auth.uid == userId
          && "attending" in request.resource.data;

    }
  }
}

(Facultatif) Vous pouvez maintenant consulter les résultats en cliquant sur les boutons. Accédez à votre tableau de bord Cloud Firestore dans la console Firebase.

Aperçu de l'application

10. Félicitations !

Vous avez utilisé Firebase pour créer une application Web interactive en temps réel !

Ce que nous avons couvert

  • Authentification Firebase
  • Cloud Firestore
  • Règles de sécurité Firebase

Prochaines étapes

  • Vous voulez en savoir plus sur les autres produits Firebase ? Peut-être souhaitez-vous stocker des fichiers image que les utilisateurs téléchargent ? Ou envoyer des notifications à vos utilisateurs ? Consultez la documentation Firebase . Vous voulez en savoir plus sur les plugins Flutter pour Firebase ? Consultez FlutterFire pour plus d' informations.
  • Vous voulez en savoir plus sur Cloud Firestore ? Vous souhaitez peut-être en savoir plus sur les sous-collections et les transactions ? Rendez -vous sur la codelab web Nuage Firestore pour une codelab qui va plus en profondeur sur le Cloud Firestore. Ou regardez cette série YouTube pour apprendre à connaître Nuage Firestore !

Apprendre encore plus

Comment c'était?

Nous aimerions vos retours. S'il vous plaît remplir un court formulaire (très) ici .