Desarrollo local para tus aplicaciones Flutter usando Firebase Emulator Suite

1. Antes de comenzar

En este codelab, aprenderá cómo usar Firebase Emulator Suite con Flutter durante el desarrollo local. Aprenderá cómo utilizar la autenticación de contraseña de correo electrónico a través de Emulator Suite y cómo leer y escribir datos en el emulador de Firestore. Finalmente, trabajará con la importación y exportación de datos desde los emuladores, para trabajar con los mismos datos falsos cada vez que regrese al desarrollo.

Requisitos previos

Este codelab asume que tienes algo de experiencia con Flutter. De lo contrario, es posible que desees aprender primero los conceptos básicos. Los siguientes enlaces son útiles:

También debes tener algo de experiencia en Firebase, pero está bien si nunca agregaste Firebase a un proyecto de Flutter. Si no está familiarizado con Firebase console o es completamente nuevo en Firebase, consulte primero los siguientes enlaces:

Lo que crearás

Este codelab lo guiará en la creación de una aplicación de registro de diario simple. La aplicación tendrá una pantalla de inicio de sesión y una pantalla que le permitirá leer entradas de diario anteriores y crear otras nuevas.

cd5c4753bbee8af.png8cb4d21f656540bf.png

lo que aprenderás

Aprenderá cómo comenzar a usar Firebase y cómo integrar y usar el paquete Firebase Emulator en su flujo de trabajo de desarrollo de Flutter. Se cubrirán estos temas de Firebase:

Tenga en cuenta que estos temas se tratan en la medida en que sean necesarios para cubrir el conjunto de emuladores de Firebase. Este codelab se centra en agregar un proyecto de Firebase a su aplicación Flutter y desarrollarlo utilizando Firebase Emulator Suite. No habrá discusiones en profundidad sobre Firebase Authentication o Firestore. Si no está familiarizado con estos temas, le recomendamos comenzar con el laboratorio de código Conociendo Firebase para Flutter .

Lo que necesitarás

  • Conocimiento práctico de Flutter y el SDK instalado.
  • Editores de texto Intellij JetBrains o VS Code
  • Navegador Google Chrome (u otro objetivo de desarrollo preferido para Flutter. Algunos comandos de terminal en este codelab asumirán que estás ejecutando tu aplicación en Chrome)

2. Crea y configura un proyecto de Firebase

La primera tarea que deberá completar es crear un proyecto de Firebase en la consola web de Firebase. La gran mayoría de este codelab se centrará en Emulator Suite, que utiliza una interfaz de usuario que se ejecuta localmente, pero primero debes configurar un proyecto completo de Firebase.

Crear un proyecto de Firebase

  1. Inicie sesión en la consola de Firebase.
  2. En Firebase console, haz clic en Agregar proyecto (o Crear un proyecto ) e ingresa un nombre para tu proyecto de Firebase (por ejemplo, " Firebase-Flutter-Codelab") .

fe6aeab3b91965ed.png

  1. Haga clic en las opciones de creación de proyectos. Acepte los términos de Firebase si se le solicita. Omita la configuración de Google Analytics, ya que no utilizará Analytics para esta aplicación.

d1fcec48bf251eaa.png

Para obtener más información sobre los proyectos de Firebase, consulte Comprender los proyectos de Firebase .

La aplicación que estás creando utiliza dos productos de Firebase que están disponibles para las aplicaciones de Flutter:

  • Autenticación de Firebase para permitir que sus usuarios inicien sesión en su aplicación.
  • Cloud Firestore para guardar datos estructurados en la nube y recibir notificaciones instantáneas cuando los datos cambian.

Estos dos productos necesitan una configuración especial o deben habilitarse mediante Firebase console.

Habilitar Cloud Firestore

La aplicación Flutter usa Cloud Firestore para guardar entradas de diario.

Habilite Cloud Firestore:

  1. En la sección Compilación de Firebase console, haz clic en Cloud Firestore .
  2. Haga clic en Crear base de datos . 99e8429832d23fa3.png
  3. Seleccione la opción Iniciar en modo de prueba . Lea el descargo de responsabilidad sobre las reglas de seguridad. El modo de prueba garantiza que pueda escribir libremente en la base de datos durante el desarrollo. Haga clic en Siguiente . 6be00e26c72ea032.png
  4. Seleccione la ubicación de su base de datos (puede usar la predeterminada). Tenga en cuenta que esta ubicación no se puede cambiar más adelante. 278656eefcfb0216.png
  5. Haga clic en Habilitar .

3. Configura la aplicación Flutter

Deberá descargar el código de inicio e instalar Firebase CLI antes de comenzar.

Obtener el código de inicio

Clona el repositorio de GitHub desde la línea de comando:

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

Alternativamente, si tiene instalada la herramienta CLI de GitHub :

gh repo clone flutter/codelabs flutter-codelabs

El código de muestra debe clonarse en el directorio flutter-codelabs , que contiene el código de una colección de codelabs. El código para este codelab está en flutter-codelabs/firebase-emulator-suite .

La estructura de directorios en flutter-codelabs/firebase-emulator-suite son dos proyectos de Flutter. Uno se llama complete , al que puede hacer referencia si desea avanzar o hacer una referencia cruzada de su propio código. El otro proyecto se llama start .

El código con el que desea comenzar está en el directorio flutter-codelabs/firebase-emulator-suite/start . Abra o importe ese directorio a su IDE preferido.

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

Instalar Firebase CLI

Firebase CLI proporciona herramientas para administrar sus proyectos de Firebase. Se requiere la CLI para utilizar Emulator Suite, por lo que deberá instalarla.

Hay varias formas de instalar la CLI. La forma más sencilla, si utilizas MacOS o Linux, es ejecutar este comando desde tu terminal:

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

Después de instalar la CLI, debes autenticarte con Firebase.

  1. Inicie sesión en Firebase con su cuenta de Google ejecutando el siguiente comando:
firebase login
  1. Este comando conecta su máquina local a Firebase y le otorga acceso a sus proyectos de Firebase.
  1. Pruebe que la CLI esté instalada correctamente y tenga acceso a su cuenta enumerando sus proyectos de Firebase. Ejecute el siguiente comando:
firebase projects:list
  1. La lista mostrada debe ser la misma que la de los proyectos de Firebase enumerados en Firebase console . Deberías ver al menos firebase-flutter-codelab.

Instale la CLI de FlutterFire

FlutterFire CLI está construido sobre Firebase CLI y facilita la integración de un proyecto de Firebase con su aplicación Flutter.

Primero, instale la CLI:

dart pub global activate flutterfire_cli

Asegúrese de que la CLI esté instalada. Ejecute el siguiente comando dentro del directorio del proyecto Flutter y asegúrese de que la CLI genere el menú de ayuda.

flutterfire --help

Utilice Firebase CLI y FlutterFire CLI para agregar su proyecto de Firebase a su aplicación Flutter

Con las dos CLI instaladas, puedes configurar productos Firebase individuales (como Firestore), descargar los emuladores y agregar Firebase a tu aplicación Flutter con solo un par de comandos de terminal.

Primero, finalice la configuración de Firebase ejecutando lo siguiente:

firebase init

Este comando lo guiará a través de una serie de preguntas necesarias para configurar su proyecto. Estas capturas de pantalla muestran el flujo:

  1. Cuando se le solicite seleccionar funciones, seleccione "Firestore" y "Emuladores". (No existe una opción de Autenticación, ya que no utiliza una configuración que se pueda modificar desde los archivos de su proyecto Flutter). fe6401d769be8f53.png
  2. A continuación, seleccione "Usar un proyecto existente" cuando se le solicite.

f11dcab439e6ac1e.png

  1. Ahora, seleccione el proyecto que creó en el paso anterior: flutter-firebase-codelab.

3bdc0c6934991c25.png

  1. A continuación, se le harán una serie de preguntas sobre cómo nombrar los archivos que se generarán. Sugiero presionar "enter" para cada pregunta para seleccionar la opción predeterminada. 9bfa2d507e199c59.png
  2. Finalmente, necesitarás configurar los emuladores. Seleccione Firestore y Autenticación de la lista y luego presione "Entrar" para cada pregunta sobre los puertos específicos que se usarán para cada emulador. Debe seleccionar el valor predeterminado, Sí, cuando se le pregunte si desea utilizar la interfaz de usuario del emulador.

Al final del proceso, debería ver un resultado similar a la siguiente captura de pantalla.

Importante : su resultado puede ser ligeramente diferente al mío, como se ve en la captura de pantalla a continuación, porque la pregunta final será "No" de manera predeterminada si ya tiene los emuladores descargados.

8544e41037637b07.png

Configurar FlutterFire

A continuación, puedes usar FlutterFire para generar el código Dart necesario para usar Firebase en tu aplicación Flutter.

flutterfire configure

Cuando se ejecuta este comando, se le pedirá que seleccione qué proyecto de Firebase desea usar y qué plataformas desea configurar. En este codelab, los ejemplos usan Flutter Web, pero puedes configurar tu proyecto de Firebase para usar todas las opciones.

Las siguientes capturas de pantalla muestran las preguntas que deberá responder.

619b7aca6dc15472.png301c9534f594f472.png

Esta captura de pantalla muestra el resultado al final del proceso. Si está familiarizado con Firebase, notará que no tuvo que crear aplicaciones en la consola y FlutterFire CLI lo hizo por usted.

12199a85ade30459.png

Agregue paquetes de Firebase a la aplicación Flutter

El último paso de configuración es agregar los paquetes de Firebase relevantes a su proyecto Flutter. En la terminal, asegúrate de estar en la raíz del proyecto Flutter en flutter-codelabs/firebase-emulator-suite/start . Luego, ejecute los tres comandos siguientes:

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

Estos son los únicos paquetes que utilizará en esta aplicación.

4. Habilitar los emuladores de Firebase

Hasta ahora, la aplicación Flutter y su proyecto Firebase están configurados para poder usar los emuladores, pero aún necesita indicarle al código Flutter que redirija las solicitudes salientes de Firebase a los puertos locales.

Primero, agregue el código de inicialización de Firebase y el código de configuración del emulador a la función main en main.dart.

dardo.principal

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

Las primeras líneas de código inicializan Firebase. Casi universalmente, si estás trabajando con Firebase en una aplicación Flutter, debes comenzar llamando a WidgetsFlutterBinding.ensureInitialized y Firebase.initializeApp .

Después de eso, el código que comienza con la línea if (kDebugMode) le indica a su aplicación que se dirija a los emuladores en lugar de a un proyecto de producción de Firebase. kDebugMode garantiza que el objetivo de los emuladores solo se realizará si se encuentra en un entorno de desarrollo. Debido a que kDebugMode es un valor constante, el compilador de Dart sabe que debe eliminar ese bloque de código por completo en el modo de lanzamiento.

Iniciar los emuladores

Debes iniciar los emuladores antes de iniciar la aplicación Flutter. Primero, inicia los emuladores ejecutando esto en la terminal:

firebase emulators:start

Este comando inicia los emuladores y expone los puertos del host local con los que podemos interactuar con ellos. Cuando ejecute ese comando, debería ver un resultado similar a este:

bb7181eb70829606.png

Este resultado le indica qué emuladores se están ejecutando y dónde puede ir para verlos. Primero, consulte la interfaz de usuario del emulador en localhost:4000 .

11563f4c7216de81.png

Esta es la página de inicio de la interfaz de usuario del emulador local. Enumera todos los emuladores disponibles y cada uno está etiquetado con estado activado o desactivado.

5. El emulador de autenticación de Firebase

El primer emulador que utilizará es el emulador de autenticación. Comience con el emulador de autenticación haciendo clic en "Ir al emulador" en la tarjeta de autenticación en la interfaz de usuario y verá una página similar a esta:

3c1bfded40733189.png

Esta página tiene similitudes con la página de la consola web de autenticación. Tiene una tabla que enumera los usuarios como la consola en línea y le permite agregar usuarios manualmente. Una gran diferencia aquí es que la única opción de método de autenticación disponible en los emuladores es mediante correo electrónico y contraseña. Esto es suficiente para el desarrollo local.

A continuación, recorrerá el proceso de agregar un usuario al emulador Firebase Auth y luego iniciar sesión con ese usuario a través de la interfaz de usuario de Flutter.

Agregar un usuario

Haga clic en el botón "Agregar usuario" y complete el formulario con esta información:

  • Nombre simplificado: guión
  • Correo electrónico: dash@email.com
  • Contraseña: palabra escrita

Envíe el formulario y verá que la tabla ahora incluye un usuario. Ahora puedes actualizar el código para iniciar sesión con ese usuario.

logged_out_view.dart

El único código en el widget LoggedOutView que debe actualizarse es la devolución de llamada que se activa cuando un usuario presiona el botón de inicio de sesión. Actualice el código para que se vea así:

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

El código actualizado reemplaza las cadenas TODO con el correo electrónico y la contraseña que creó en el emulador de autenticación. Y en la siguiente línea, la línea if(true) ha sido reemplazada por un código que verifica si state.user es nulo. El código de AppClass arroja más luz sobre esto.

aplicación_estado.dart

Es necesario actualizar dos partes del código en AppState . Primero, asigne al miembro de la clase AppState.user el tipo User del paquete firebase_auth , en lugar del tipo Object .

En segundo lugar, complete el método AppState.login como se muestra a continuación:

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 definición de tipo para usuario ahora es User? . Esa clase User proviene de Firebase Auth y proporciona información necesaria, como User.displayName , que se analiza más adelante.

Este es el código básico necesario para iniciar sesión como usuario con un correo electrónico y contraseña en Firebase Auth. Realiza una llamada a FirebaseAuth para iniciar sesión, lo que devuelve un objeto Future<UserCredential> . Cuando se completa el futuro, este código verifica si hay un User adjunto a UserCredential . Si hay un usuario en el objeto de credencial, entonces un usuario ha iniciado sesión correctamente y se puede configurar la propiedad AppState.user . Si no lo hay, entonces hubo un error y se imprime.

Tenga en cuenta que la única línea de código en este método que es específica de esta aplicación (en lugar del código general de FirebaseAuth) es la llamada al método _listenForEntries , que se tratará en el siguiente paso.

TODO: Icono de acción: recarga tu aplicación y luego presiona el botón Iniciar sesión cuando se muestre. Esto hace que la aplicación navegue a una página que dice "¡Bienvenido de nuevo, persona!" en la cima. La autenticación debe estar funcionando porque le permite navegar a esta página, pero se debe realizar una actualización menor en logged_in_view.dart para mostrar el nombre real del usuario.

logged_in_view.dart

Cambie la primera línea en el método 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(
 // ...

Ahora, esta línea toma el displayName de la propiedad User en el objeto AppState . Este displayName se configuró en el emulador cuando definió su primer usuario. Tu aplicación ahora debería mostrar "¡Bienvenido de nuevo, Dash!" cuando inicias sesión, en lugar de TODO .

6. Leer y escribir datos en el emulador de Firestore

Primero, consulte el emulador de Firestore. En la página de inicio de la interfaz de usuario del emulador ( localhost:4000 ), haga clic en "Ir al emulador" en la tarjeta Firestore. Debe tener un aspecto como este:

Emulador:

791fce7dc137910a.png

Consola de base de fuego:

e0dde9aea34af050.png

Si tiene alguna experiencia con Firestore, notará que esta página es similar a la página de Firestore de la consola Firebase. Sin embargo, existen algunas diferencias notables.

  1. Puede borrar todos los datos con solo tocar un botón. Esto sería peligroso con los datos de producción, ¡pero es útil para una iteración rápida! Si está trabajando en un nuevo proyecto y su modelo de datos cambia, es fácil borrarlo.
  2. Hay una pestaña "Solicitudes". Esta pestaña le permite ver las solicitudes entrantes realizadas a este emulador. Discutiré esta pestaña con más detalle en un momento.
  3. No hay pestañas para Reglas, Índices o Uso. Existe una herramienta (que se analiza en la siguiente sección) que ayuda a escribir reglas de seguridad, pero no puede establecer reglas de seguridad para el emulador local.

Para resumir esa lista, esta versión de Firestore proporciona más herramientas útiles durante el desarrollo y elimina herramientas que son necesarias en producción.

Escribir a Firestore

Antes de hablar sobre la pestaña 'Solicitudes' en el emulador, primero haga una solicitud. Esto requiere actualizaciones de código. Comience conectando el formulario en la aplicación para escribir una nueva Entry del diario en Firestore.

El flujo de alto nivel para enviar una Entry es:

  1. El usuario completa el formulario y presiona el botón Submit
  2. La interfaz de usuario llama a AppState.writeEntryToFirebase
  3. AppState.writeEntryToFirebase agrega una entrada a Firebase

No es necesario cambiar ninguno de los códigos involucrados en los pasos 1 o 2. El único código que debe agregarse para el paso 3 se agregará en la clase AppState . Realice el siguiente cambio en AppState.writeEntryToFirebase .

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

El código del método writeEntryToFirebase toma una referencia a la colección llamada "Entries" en Firestore. Luego agrega una nueva entrada, que debe ser del tipo Map<String, String> .

En este caso, la colección "Entradas" en Firestore no existía, por lo que Firestore creó una.

Con ese código agregado, vuelva a cargar o reinicie su aplicación, inicie sesión y navegue hasta la vista EntryForm . Puede completar el formulario con las Strings que desee. (El campo Fecha aceptará cualquier cadena, ya que se ha simplificado para este codelab. No tiene una validación sólida ni se preocupa por los objetos DateTime de ninguna manera).

Presione enviar en el formulario. No sucederá nada en la aplicación, pero podrás ver tu nueva entrada en la interfaz de usuario del emulador.

La pestaña de solicitudes en el emulador de Firestore

En la interfaz de usuario, navega hasta el emulador de Firestore y mira la pestaña "Datos". Deberías ver que ahora hay una Colección en la raíz de tu base de datos llamada "Entradas". Debe tener un documento que contenga la misma información que ingresó en el formulario.

a978fb34fb8a83da.png

Eso confirma que AppState.writeEntryToFirestore funcionó y ahora puede explorar más a fondo la solicitud en la pestaña Solicitudes. Haga clic en esa pestaña ahora.

Solicitudes del emulador de Firestore

Aquí debería ver una lista similar a esta:

f0b37f0341639035.png

Puede hacer clic en cualquiera de esos elementos de la lista y ver bastante información útil. Haga clic en el elemento de la lista CREATE que corresponda a su solicitud para crear un nuevo asiento de diario. Verás una nueva tabla similar a esta:

385d62152e99aad4.png

Como se mencionó, el emulador de Firestore proporciona herramientas para desarrollar las reglas de seguridad de su aplicación. Esta vista muestra exactamente qué línea en sus reglas de seguridad pasó esta solicitud (o falló, si ese fuera el caso). En una aplicación más sólida, las reglas de seguridad pueden crecer y tener múltiples comprobaciones de autorización. Esta vista se utiliza para ayudar a escribir y depurar esas reglas de autorización.

También proporciona una manera sencilla de inspeccionar cada parte de esta solicitud, incluidos los metadatos y los datos de autenticación. Estos datos se utilizan para escribir reglas de autorización complejas.

Leyendo desde Firestore

Firestore utiliza la sincronización de datos para enviar datos actualizados a los dispositivos conectados. En el código de Flutter, puedes escuchar (o suscribirte) a las colecciones y documentos de Firestore, y tu código será notificado cada vez que cambien los datos. En esta aplicación, la escucha de las actualizaciones de Firestore se realiza mediante el método llamado AppState._listenForEntries .

Este código funciona junto con StreamController y Stream llamados AppState._entriesStreamController y AppState.entries , respectivamente. Ese código ya está escrito, al igual que todo el código necesario en la interfaz de usuario para mostrar los datos de Firestore.

Actualice el método _listenForEntries para que coincida con el siguiente código:

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

Este código escucha la colección "Entradas" en Firestore. Cuando Firestore notifica a este cliente que hay datos nuevos, pasa esos datos y el código en _listenForEntries cambia todos sus documentos secundarios a un objeto que nuestra aplicación puede usar ( Entry ). Luego, agrega esas entradas al StreamController llamado _entriesStreamController (que la interfaz de usuario está escuchando). Este código es la única actualización requerida.

Finalmente, recuerde que el método AppState.logIn realiza una llamada a _listenForEntries , que comienza el proceso de escucha después de que un usuario haya iniciado sesión.

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

Ahora ejecuta la aplicación. Debe tener un aspecto como este:

b8a31c7a8900331.gif

7. Exportar e importar datos al emulador.

Los emuladores de Firebase admiten la importación y exportación de datos. El uso de importaciones y exportaciones le permite continuar el desarrollo con los mismos datos cuando toma un descanso del desarrollo y luego lo reanuda. También puedes enviar archivos de datos a git, y otros desarrolladores con los que estés trabajando tendrán los mismos datos para trabajar.

Exportar datos del emulador

Primero, exporta los datos del emulador que ya tienes. Mientras los emuladores aún se están ejecutando, abra una nueva ventana de terminal e ingrese el siguiente comando:

firebase emulators:export ./emulators_data

.emulators_data es un argumento que le indica a Firebase dónde exportar los datos. Si el directorio no existe, se crea. Puede utilizar cualquier nombre que desee para ese directorio.

Cuando ejecute este comando, verá este resultado en la terminal donde ejecutó el comando:

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

Y si cambia a la ventana de terminal donde se ejecutan los emuladores, verá este resultado:

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

Y finalmente, si buscas en el directorio de tu proyecto, deberías ver un directorio llamado ./emulators_data , que contiene archivos JSON , entre otros archivos de metadatos, con los datos que has guardado.

Importar datos del emulador

Ahora puede importar esos datos como parte de su flujo de trabajo de desarrollo y comenzar donde lo dejó.

Primero, detenga los emuladores si se están ejecutando presionando CTRL+C en su terminal.

A continuación, ejecute el comando emulators:start que ya ha visto, pero con una bandera que le indica qué datos importar:

firebase emulators:start --import ./emulators_data

Cuando los emuladores estén activos, navegue hasta la interfaz de usuario del emulador en localhost:4000 y debería ver los mismos datos con los que estaba trabajando anteriormente.

Exportar datos automáticamente al cerrar emuladores

También puedes exportar datos automáticamente cuando sales de los emuladores, en lugar de recordar exportar los datos al final de cada sesión de desarrollo.

Cuando inicie sus emuladores, ejecute el comando emulators:start con dos indicadores adicionales.

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

¡Voilá! Sus datos ahora se guardarán y recargarán cada vez que trabaje con los emuladores para este proyecto. También puede especificar un directorio diferente como argumento para el –export-on-exit flag , pero de forma predeterminada será el directorio pasado a –import .

También puede utilizar cualquier combinación de estas opciones. Esta es la nota de los documentos : el directorio de exportación se puede especificar con esta bandera: firebase emulators:start --export-on-exit=./saved-data . Si se utiliza --import , la ruta de exportación por defecto es la misma; por ejemplo: firebase emulators:start --import=./data-path --export-on-exit . Por último, si lo desea, pase diferentes rutas de directorio a los indicadores --import y --export-on-exit .

8. ¡Felicitaciones!

Has completado la puesta en marcha con el emulador de Firebase y Flutter. Puede encontrar el código completo para este Codelab en el directorio "completo" en github: Flutter Codelabs

Lo que hemos cubierto

  • Configurar una aplicación Flutter para usar Firebase
  • Configurar un proyecto de Firebase
  • CLI de FlutterFire
  • CLI de base de fuego
  • Emulador de autenticación de Firebase
  • Emulador de Firebase Firestore
  • Importar y exportar datos del emulador

Próximos pasos

Aprende más

¡Sparky está orgulloso de ti!

2a0ad195769368b1.gif