Desarrollo local de tus apps de Flutter con Firebase Emulator Suite

1. Antes de comenzar

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

Requisitos previos

En este codelab, se presupone que tienes experiencia en Flutter. Si no es así, te recomendamos que primero aprendas los conceptos básicos. Los siguientes vínculos son útiles:

También deberías tener algo de experiencia con Firebase, pero no te preocupes si nunca lo agregaste a un proyecto de Flutter. Si no conoces Firebase console o es la primera vez que usas Firebase, consulta primero los siguientes vínculos:

Qué crearás

En este codelab, se te guiará para que compiles una aplicación simple de Journaling. La aplicación tendrá una pantalla de acceso y una pantalla en la que podrás leer las entradas del diario anterior y crear nuevas.

cd5c4753bbee8af.png 8cb4d21f656540bf.png

Qué aprenderás

Aprenderás a comenzar a usar Firebase y a integrar y usar Firebase Emulator Suite en tu flujo de trabajo de desarrollo de Flutter. Se tratarán los siguientes temas de Firebase:

Ten en cuenta que estos temas se abordan en la medida en que son necesarios para explicar el paquete de emuladores de Firebase. Este codelab se enfoca en agregar un proyecto de Firebase a tu app de Flutter y desarrollar con Firebase Emulator Suite. No habrá debates detallados sobre Firebase Authentication o Firestore. Si no conoces estos temas, te recomendamos que comiences con el codelab Introducción a Firebase para Flutter.

Requisitos

  • Conocimiento práctico sobre Flutter y el SDK instalado
  • Editores de texto de Intellij JetBrains o VS Code
  • Navegador Google Chrome (o tu otro destino de desarrollo preferido para Flutter) Algunos comandos de terminal de este codelab supondrán que ejecutas tu app en Chrome).

2. Crea y configura un proyecto de Firebase

Lo primero que debes completar es crear un proyecto de Firebase en la consola web de Firebase. La gran mayoría de este codelab se enfocará en Emulator Suite, que usa una IU que se ejecuta localmente, pero primero debes configurar un proyecto completo de Firebase.

Crea un proyecto de Firebase

  1. Accede a Firebase console.
  2. En Firebase console, haz clic en Agregar proyecto (o Crear un proyecto) y, luego, ingresa un nombre para tu proyecto de Firebase (por ejemplo, "Firebase-Flutter-Codelab").

fe6aeab3b91965ed.png

  1. Haz clic para avanzar por las opciones de creación de proyectos. Si se te solicita, acepta las condiciones de Firebase. Omite la configuración de Google Analytics, ya que no utilizarás ese servicio en esta app.

d1fcec48bf251eaa.png

Para obtener más información sobre los proyectos de Firebase, consulta la Información sobre los proyectos de Firebase.

La app que estás compilando usa dos productos de Firebase que están disponibles para apps de Flutter:

  • Firebase Authentication para permitir que los usuarios accedan a tu app
  • Cloud Firestore para guardar datos estructurados en la nube y recibir notificaciones instantáneas cuando cambien los datos

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

Habilita Cloud Firestore

La app de Flutter usa Cloud Firestore para guardar las entradas del diario.

Habilita Cloud Firestore:

  1. En la sección Compilación de Firebase console, haz clic en Cloud Firestore.
  2. Haz clic en Crear base de datos. 99e8429832d23fa3.png
  3. Selecciona la opción Comenzar en modo de prueba. Lee la renuncia de responsabilidad sobre las reglas de seguridad. El modo de prueba garantiza que puedas escribir con libertad en la base de datos durante el desarrollo. Haz clic en Siguiente. 6be00e26c72ea032.png
  4. Selecciona la ubicación de tu base de datos (puedes usar la predeterminada). Ten en cuenta que esta ubicación no se puede cambiar más adelante. 278656eefcfb0216.png
  5. Haz clic en Habilitar.

3. Configura la app de Flutter

Debes descargar el código de partida y, luego, instalar Firebase CLI antes de comenzar.

Obtén el código de partida

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

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

Como alternativa, si tienes instalada la herramienta de CLI de GitHub, haz lo siguiente:

gh repo clone flutter/codelabs flutter-codelabs

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

La estructura de directorios de flutter-codelabs/firebase-emulator-suite consta de dos proyectos de Flutter. Una se llama complete, que puedes consultar si deseas adelantar o hacer una referencia cruzada de tu propio código. El otro proyecto se llama start.

El código con el que quieres comenzar se encuentra en el directorio flutter-codelabs/firebase-emulator-suite/start. Abre o importa ese directorio en el IDE que prefieras.

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

Instala Firebase CLI

Firebase CLI proporciona herramientas para administrar tus proyectos de Firebase. La CLI es necesaria para usar Emulator Suite, por lo que deberás instalarla.

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

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

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

  1. Accede a Firebase con tu Cuenta de Google ejecutando el siguiente comando:
firebase login
  1. Este comando conecta tu máquina local a Firebase y te otorga acceso a tus proyectos de Firebase.
  1. Enumera tus proyectos de Firebase para probar que la CLI se instaló correctamente y que tiene acceso a tu cuenta. Ejecuta el siguiente comando:
firebase projects:list
  1. La lista que se muestra debe ser la misma que los proyectos de Firebase enumerados en Firebase console. Deberías ver al menos firebase-flutter-codelab.

Instala la CLI de FlutterFire

La CLI de FlutterFire se compila sobre Firebase CLI y facilita la integración de un proyecto de Firebase con tu app de Flutter.

Primero, instala la CLI:

dart pub global activate flutterfire_cli

Asegúrate de que se haya instalado la CLI. Ejecuta el siguiente comando en el directorio del proyecto de Flutter y asegúrate de que la CLI muestre el menú de ayuda.

flutterfire --help

Usa Firebase CLI y FlutterFire CLI para agregar tu proyecto de Firebase a tu app de Flutter

Con las dos CLI instaladas, puedes configurar productos individuales de Firebase (como Firestore), descargar los emuladores y agregar Firebase a tu app de Flutter con solo algunos comandos de la terminal.

Primero, ejecuta el siguiente comando para finalizar la configuración de Firebase:

firebase init

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

  1. Cuando se te solicite que selecciones funciones, elige “Firestore” y “Emuladores”. (No hay una opción de autenticación, ya que no usa la configuración que se puede modificar desde los archivos de tu proyecto de Flutter). fe6401d769be8f53.png
  2. Luego, selecciona “Usar un proyecto existente” cuando se te solicite.

f11dcab439e6ac1e.png

  1. Ahora, selecciona el proyecto que creaste en un paso anterior: flutter-firebase-codelab.

3bdc0c6934991c25.png

  1. A continuación, se te hará una serie de preguntas sobre la asignación de nombres a los archivos que se generarán. Sugerimos presionar "Intro" de cada pregunta para seleccionar la opción predeterminada. 9bfa2d507e199c59.png
  2. Por último, deberás configurar los emuladores. Selecciona Firestore y Authentication en la lista y, luego, presiona “Intro” a cada pregunta sobre los puertos específicos que se deben usar para cada emulador. Debes seleccionar la opción predeterminada Sí (Yes) cuando se te pregunte si deseas usar la IU del emulador.

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

Importante: Es posible que tu resultado sea un poco diferente al mío, como se muestra en la siguiente captura de pantalla, ya que la pregunta final será "No" de forma predeterminada. si ya descargaste los emuladores.

8544e41037637b07.png

Configura FlutterFire

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

flutterfire configure

Cuando se ejecute este comando, se te pedirá que selecciones el proyecto de Firebase que quieres usar y las plataformas que deseas 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 indicaciones que deberás responder.

619b7aca6dc15472.png 301c9534f594f472.png

En esta captura de pantalla, se muestra el resultado al final del proceso. Si conoces Firebase, notarás que no tuviste que crear aplicaciones en la consola, y la CLI de FlutterFire lo hizo por ti.

12199a85ade30459.png

Agrega paquetes de Firebase a la app de Flutter

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

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

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

4. Habilita los emuladores de Firebase

Hasta ahora, la app de Flutter y tu proyecto de Firebase están configurados para poder usar los emuladores, pero, de todos modos, debes indicarle al código de Flutter que redirija las solicitudes salientes de Firebase a los puertos locales.

Primero, agrega 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..

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

Las primeras líneas de código inicializan Firebase. Casi siempre, si trabajas con Firebase en una app de Flutter, debes comenzar por llamar a WidgetsFlutterBinding.ensureInitialized y Firebase.initializeApp.

Luego, el código que comienza con la línea if (kDebugMode) le indica a tu app que se oriente a los emuladores en lugar de a un proyecto de producción de Firebase. kDebugMode garantiza que la orientación a los emuladores solo se produzca si estás en un entorno de desarrollo. Como kDebugMode es un valor constante, el compilador de Dart sabe que debe quitar todo el bloque de código en el modo de lanzamiento.

Inicia los emuladores

Debes iniciar los emuladores antes de iniciar la app de Flutter. Primero, inicia los emuladores ejecutando lo siguiente en la terminal:

firebase emulators:start

Este comando inicia los emuladores y expone los puertos localhost con los que podemos interactuar. Cuando ejecutes ese comando, deberías ver un resultado similar al siguiente:

bb7181eb70829606.png

Este resultado te indica qué emuladores se están ejecutando y dónde puedes verlos. Primero, consulta la IU del emulador en localhost:4000.

11563f4c7216de81.png

Esta es la página principal de la IU del emulador local. Se muestran todos los emuladores disponibles, y cada uno está etiquetado con el estado activado o desactivado.

5. El emulador de Firebase Auth

El primer emulador que usarás es el emulador de Authentication. Haz clic en “Go to Emulator” para comenzar con el emulador de Auth. en la tarjeta Autenticación de la IU, verás una página como la siguiente:

8c1bfded40733189.png

Esta página tiene similitudes con la página de la consola web de Auth. Tiene una tabla con una lista de los usuarios, como la consola en línea, y te permite agregar usuarios de forma manual. 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, analizarás el proceso de agregar un usuario al emulador de Firebase Authentication y, luego, accederás a ese usuario a través de la IU de Flutter.

Agrega un usuario

Haz clic en el botón "Agregar usuario" y completa el formulario con la siguiente información:

  • Nombre visible: Dash
  • Correo electrónico: dash@email.com
  • Contraseña: dashword

Envía el formulario y verás que la tabla ahora incluye un usuario. Ahora puedes actualizar el código para acceder con ese usuario.

logged_out_view.dart

El único código del widget LoggedOutView que se debe actualizar está en la devolución de llamada que se activa cuando un usuario presiona el botón de acceso. Actualiza el código para que se vea de la siguiente manera:

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 por el correo electrónico y la contraseña que creaste en el emulador de Auth. En la siguiente línea, se reemplazó la línea if(true) por un código que verifica si state.user es nulo. El código en AppClass arroja más luz sobre esto.

app_state.dart

Se deben actualizar dos partes del código de AppState. Primero, asigna al miembro de clase AppState.user el tipo User del paquete firebase_auth, en lugar del tipo Object.

En segundo lugar, completa 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 el usuario ahora es User?. Esa clase User proviene de Firebase Auth y proporciona información necesaria, como User.displayName, que se analizará más adelante.

Este es el código básico necesario para que un usuario acceda con un correo electrónico y una contraseña en Firebase Auth. Realiza una llamada a FirebaseAuth para acceder, lo que muestra un objeto Future<UserCredential>. Cuando se completa el futuro, este código comprueba si hay un User adjunto al UserCredential. Si hay un usuario en el objeto de credenciales, significa que un usuario accedió correctamente y se puede configurar la propiedad AppState.user. De lo contrario, se produjo un error y se imprime.

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

TODO: Ícono de acción: Vuelve a cargar la app y, luego, presiona el botón de acceso cuando se renderice. Esto hace que la app navegue a una página que diga "Welcome Back, Person!". en la parte superior. La autenticación debe funcionar, ya que te permite navegar a esta página. Sin embargo, se debe realizar una actualización menor en logged_in_view.dart para que se muestre el nombre real del usuario.

logged_in_view.dart

Cambia la primera línea del 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 definiste tu primer usuario. Ahora, tu app debería mostrar el mensaje "Welcome back, Dash!". cuando accedes, en lugar de TODO.

6. Lee y escribe datos en el emulador de Firestore

Primero, consulta el emulador de Firestore. En la página principal de la IU del emulador (localhost:4000), haz clic en "Go to Emulator". en la tarjeta de Firestore. Se verá de la siguiente manera:

Emulador:

80fce7dc137910a.png

Firebase console:

e0dde9aea34af050.png

Si tienes experiencia con Firestore, notarás que esta página se parece a la página de Firestore de Firebase console. Sin embargo, existen algunas diferencias notables.

  1. Puedes borrar todos los datos con solo presionar un botón. Esto sería peligroso con los datos de producción, pero es útil para la iteración rápida. Si estás trabajando en un proyecto nuevo y tu modelo de datos cambia, es fácil borrarlo.
  2. Hay una sección de "Solicitudes" . Esta pestaña te permite observar las solicitudes entrantes que se realizan a este emulador. Hablaremos de esta pestaña con más detalle en breve.
  3. No hay pestañas para Reglas, Índices ni Uso. Existe una herramienta (que se analiza en la siguiente sección) que ayuda a escribir reglas de seguridad, pero no puedes establecer reglas de seguridad para el emulador local.

En resumen, esta versión de Firestore proporciona más herramientas útiles durante el desarrollo y quita las herramientas que se necesitan en producción.

Escribe en Firestore

Antes de analizar las "Solicitudes" del emulador, primero realiza una solicitud. Esto requiere actualizaciones de código. Primero, conecta el formulario en la app para escribir un nuevo diario Entry en Firestore.

El flujo de alto nivel para enviar un Entry es el siguiente:

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

No es necesario cambiar el código del paso 1 o 2. El único código que se debe agregar para el paso 3 se agregará en la clase AppState. Realiza el siguiente cambio en 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,
   });
 }
 // ...
}

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

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

Con ese código agregado, vuelve a cargar en caliente o reinicia la app, accede y navega a la vista de EntryForm. Puedes completar el formulario con cualquier Strings que desees. (El campo Fecha aceptará cualquier cadena, ya que se simplificó para este codelab. No tiene una validación sólida ni se preocupa por los objetos DateTime de ninguna manera).

Presiona Enviar en el formulario. No sucederá nada en la app, pero puedes ver tu nueva entrada en la IU del emulador.

La pestaña Solicitudes en el emulador de Firestore

En la IU, navega al emulador de Firestore y observa la sección “Datos”. . Deberías ver que ahora hay una colección en la raíz de tu base de datos llamada "Entradas". Allí deberías encontrar un documento que contenga la misma información que ingresaste en el formulario.

978fb34fb8a83da.png

Esto confirma que AppState.writeEntryToFirestore funcionó y ahora puedes explorar la solicitud en la pestaña Solicitudes. Haz clic en esa pestaña ahora.

Solicitudes del emulador de Firestore

Deberías ver una lista similar a la siguiente:

f0b37f0341639035.png

Puedes hacer clic en cualquiera de esos elementos de la lista para ver información útil. Haz clic en el elemento de lista CREATE que corresponde a tu solicitud para crear una nueva entrada de registro. Verás una tabla nueva con este aspecto:

385d62152e99aad4.png

Como se mencionó antes, el emulador de Firestore proporciona herramientas para desarrollar las reglas de seguridad de las apps. Esta vista muestra exactamente qué línea de tus reglas de seguridad aprobó esta solicitud (o si falló, si ese es el caso). En una app más sólida, las reglas de seguridad pueden crecer y tener varias verificaciones de autorización. Esta vista se usa para ayudar a escribir y depurar esas reglas de autorización.

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

Lee desde Firestore

Firestore usa la sincronización de datos para enviar datos actualizados a los dispositivos conectados. En el código de Flutter, puedes detectar (o suscribirte) a colecciones y documentos de Firestore, y tu código recibirá una notificación cada vez que cambien los datos. En esta app, la detección de actualizaciones de Firestore se realiza en 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 IU para mostrar los datos de Firestore.

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

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

Este código escucha las "Entradas" en Firestore. Cuando Firestore notifica al cliente que hay datos nuevos, los pasa, y el código de _listenForEntries cambia todos sus documentos secundarios a un objeto que nuestra app puede usar (Entry). Luego, agrega esas entradas al StreamController llamado _entriesStreamController (que escucha la IU). Este código es la única actualización obligatoria.

Por último, recuerda que el método AppState.logIn realiza una llamada a _listenForEntries, que inicia el proceso de escucha después de que un usuario accede.

// ...
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 app. Debería verse de la siguiente manera:

b8a31c7a8900331.gif

7. Importa y exporta datos al emulador

Los emuladores de Firebase admiten la importación y exportación de datos. Usar las importaciones y exportaciones te permite continuar el desarrollo con los mismos datos cuando te tomas un descanso del desarrollo y, luego, lo reanudas. También puedes confirmar archivos de datos en git, y los otros desarrolladores con los que trabajas tendrán los mismos datos para trabajar.

Cómo exportar datos del emulador

Primero, exporta los datos del emulador que ya tienes. Mientras los emuladores siguen ejecutándose, abre una nueva ventana de terminal y escribe 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. Puedes usar cualquier nombre que desees para ese directorio.

Cuando ejecutes este comando, verás el siguiente resultado en la terminal en la que lo ejecutaste:

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 cambias a la ventana de la terminal en la que se ejecutan los emuladores, verás este resultado:

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

Por último, si observas 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 guardaste.

Importa datos del emulador

Ahora, puedes importar esos datos como parte de tu flujo de trabajo de desarrollo y comenzar desde donde lo dejaste.

Primero, presiona CTRL+C en la terminal para detener los emuladores si están en ejecución.

Luego, ejecuta el comando emulators:start que ya viste, pero con una marca que le indique qué datos importar:

firebase emulators:start --import ./emulators_data

Cuando los emuladores estén en funcionamiento, navega a la IU del emulador en localhost:4000 y deberías ver los mismos datos con los que trabajabas anteriormente.

Exporta datos automáticamente cuando cierres emuladores

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

Cuando inicies los emuladores, ejecuta el comando emulators:start con dos marcas adicionales.

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

¡Ya está! Ahora, tus datos se guardarán y volverán a cargarse cada vez que trabajes con los emuladores de este proyecto. También puedes especificar un directorio diferente como argumento para –export-on-exit flag, pero se usará de forma predeterminada el directorio que se pasa a –import.

También puedes usar cualquier combinación de estas opciones. Esta es la nota de la documentación: El directorio de exportación se puede especificar con la marca firebase emulators:start --export-on-exit=./saved-data. Si se usa --import, la ruta de exportación predeterminada es igual. Por ejemplo: firebase emulators:start --import=./data-path --export-on-exit. Por último, si lo deseas, pasa diferentes rutas de directorio a las marcas --import y --export-on-exit.

8. ¡Felicitaciones!

Completaste el curso Comienza a usar el emulador de Firebase y Flutter. Puedes encontrar el código completo de este codelab en la sección “complete” Directorio en GitHub: Codelabs de Flutter

Temas abordados

  • Cómo configurar una app de Flutter para usar Firebase
  • Configura un proyecto de Firebase
  • CLI de FlutterFire
  • Firebase CLI
  • Emulador de Firebase Authentication
  • Emulador de Firebase Firestore
  • Cómo importar y exportar datos del emulador

Próximos pasos

Más información

Sparky está orgulloso de ti

2a0ad195769368b1.gif