Sviluppo locale per le tue app Flutter utilizzando Firebase Emulator Suite

1. Prima di iniziare

In questo codelab imparerai come utilizzare Firebase Emulator Suite con Flutter durante lo sviluppo locale. Imparerai come utilizzare l'autenticazione tramite password e-mail tramite Emulator Suite e come leggere e scrivere dati sull'emulatore Firestore. Infine, lavorerai con l'importazione e l'esportazione dei dati dagli emulatori, per lavorare con gli stessi dati falsi ogni volta che torni allo sviluppo.

Prerequisiti

Questo codelab presuppone che tu abbia una certa esperienza con Flutter. In caso contrario, potresti voler imparare prima le basi. Sono utili i seguenti link:

Dovresti anche avere una certa esperienza con Firebase, ma va bene se non hai mai aggiunto Firebase a un progetto Flutter. Se non hai familiarità con la console Firebase o se sei completamente nuovo a Firebase, consulta prima i seguenti collegamenti:

Cosa creerai

Questo codelab ti guida nella creazione di una semplice applicazione di journaling. L'applicazione avrà una schermata di accesso e una schermata che ti consentirà di leggere le voci del diario passate e crearne di nuove.

cd5c4753bbee8af.png8cb4d21f656540bf.png

Cosa imparerai

Imparerai come iniziare a utilizzare Firebase e come integrare e utilizzare la suite Firebase Emulator nel flusso di lavoro di sviluppo Flutter. Verranno trattati i seguenti argomenti Firebase:

Tieni presente che questi argomenti vengono trattati nella misura in cui sono necessari per coprire la suite di emulatore Firebase. Questo codelab è incentrato sull'aggiunta di un progetto Firebase alla tua app Flutter e sullo sviluppo utilizzando Firebase Emulator Suite. Non ci saranno discussioni approfondite sull'autenticazione Firebase o Firestore. Se non hai familiarità con questi argomenti, ti consigliamo di iniziare con il codelab Conoscere Firebase per Flutter .

Di cosa avrai bisogno

  • Conoscenza pratica di Flutter e SDK installato
  • Editor di testo Intellij JetBrains o VS Code
  • Browser Google Chrome (o il tuo altro target di sviluppo preferito per Flutter. Alcuni comandi del terminale in questo codelab presuppongono che tu stia eseguendo la tua app su Chrome)

2. Crea e configura un progetto Firebase

La prima attività che dovrai completare è la creazione di un progetto Firebase nella console web di Firebase. La stragrande maggioranza di questo codelab si concentrerà sull'Emulator Suite, che utilizza un'interfaccia utente eseguita localmente, ma devi prima impostare un progetto Firebase completo.

Crea un progetto Firebase

  1. Accedi alla console Firebase.
  2. Nella console Firebase, fai clic su Aggiungi progetto (o Crea un progetto ) e inserisci un nome per il tuo progetto Firebase (ad esempio, " Firebase-Flutter-Codelab") .

fe6aeab3b91965ed.png

  1. Fai clic sulle opzioni di creazione del progetto. Se richiesto, accetta i termini di Firebase. Salta la configurazione di Google Analytics perché non utilizzerai Analytics per questa app.

d1fcec48bf251eaa.png

Per ulteriori informazioni sui progetti Firebase, consulta Comprendere i progetti Firebase .

L'app che stai creando utilizza due prodotti Firebase disponibili per le app Flutter:

  • Autenticazione Firebase per consentire ai tuoi utenti di accedere alla tua app.
  • Cloud Firestore per salvare i dati strutturati sul cloud e ricevere notifiche istantanee quando i dati cambiano.

Questi due prodotti necessitano di una configurazione speciale o devono essere abilitati utilizzando la console Firebase.

Abilita Cloud Firestore

L'app Flutter utilizza Cloud Firestore per salvare le voci del diario.

Abilita Cloud Firestore:

  1. Nella sezione Compila della console Firebase, fai clic su Cloud Firestore .
  2. Fare clic su Crea database . 99e8429832d23fa3.png
  3. Seleziona l'opzione Avvia in modalità test . Leggi il disclaimer sulle regole di sicurezza. La modalità test garantisce la possibilità di scrivere liberamente nel database durante lo sviluppo. Fare clic su Avanti . 6be00e26c72ea032.png
  4. Seleziona la posizione per il tuo database (puoi semplicemente utilizzare quella predefinita). Tieni presente che questa posizione non può essere modificata in seguito. 278656eefcfb0216.png
  5. Fare clic su Abilita .

3. Configura l'app Flutter

Prima di iniziare dovrai scaricare il codice iniziale e installare la CLI Firebase.

Ottieni il codice iniziale

Clona il repository GitHub dalla riga di comando:

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

In alternativa, se hai installato lo strumento cli di GitHub :

gh repo clone flutter/codelabs flutter-codelabs

Il codice di esempio deve essere clonato nella directory flutter-codelabs , che contiene il codice per una raccolta di codelab. Il codice per questo codelab è in flutter-codelabs/firebase-emulator-suite .

La struttura della directory in flutter-codelabs/firebase-emulator-suite è composta da due progetti Flutter. Uno si chiama complete , a cui puoi fare riferimento se vuoi saltare avanti o fare un riferimento incrociato al tuo codice. L'altro progetto si chiama start .

Il codice con cui vuoi iniziare si trova nella directory flutter-codelabs/firebase-emulator-suite/start . Apri o importa quella directory nel tuo IDE preferito.

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

Installa l'interfaccia a riga di comando di Firebase

La CLI Firebase fornisce strumenti per la gestione dei tuoi progetti Firebase. La CLI è necessaria per utilizzare Emulator Suite, quindi dovrai installarla.

Esistono diversi modi per installare la CLI. Il modo più semplice, se utilizzi MacOS o Linux, è eseguire questo comando dal tuo terminale:

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

Dopo aver installato la CLI, devi autenticarti con Firebase.

  1. Accedi a Firebase utilizzando il tuo account Google eseguendo il seguente comando:
firebase login
  1. Questo comando collega il tuo computer locale a Firebase e ti consente l'accesso ai tuoi progetti Firebase.
  1. Verifica che la CLI sia installata correttamente e abbia accesso al tuo account elencando i tuoi progetti Firebase. Esegui il seguente comando:
firebase projects:list
  1. L'elenco visualizzato dovrebbe essere lo stesso dei progetti Firebase elencati nella console Firebase . Dovresti vedere almeno firebase-flutter-codelab.

Installa la CLI FlutterFire

La CLI FlutterFire è basata sulla CLI Firebase e semplifica l'integrazione di un progetto Firebase con la tua app Flutter.

Innanzitutto, installa la CLI:

dart pub global activate flutterfire_cli

Assicurati che la CLI sia stata installata. Esegui il comando seguente nella directory del progetto Flutter e assicurati che la CLI visualizzi il menu della guida.

flutterfire --help

Utilizza la CLI Firebase e la CLI FlutterFire per aggiungere il tuo progetto Firebase alla tua app Flutter

Con le due CLI installate, puoi configurare singoli prodotti Firebase (come Firestore), scaricare gli emulatori e aggiungere Firebase alla tua app Flutter con solo un paio di comandi del terminale.

Innanzitutto, completa la configurazione di Firebase eseguendo quanto segue:

firebase init

Questo comando ti guiderà attraverso una serie di domande necessarie per impostare il tuo progetto. Questi screenshot mostrano il flusso:

  1. Quando viene richiesto di selezionare le funzionalità, selezionare "Firestore" ed "Emulatori". (Non esiste un'opzione di autenticazione, poiché non utilizza la configurazione modificabile dai file di progetto Flutter.) fe6401d769be8f53.png
  2. Successivamente, seleziona "Utilizza un progetto esistente", quando richiesto.

f11dcab439e6ac1e.png

  1. Ora seleziona il progetto che hai creato nel passaggio precedente: flutter-firebase-codelab.

3bdc0c6934991c25.png

  1. Successivamente, ti verranno poste una serie di domande sulla denominazione dei file che verranno generati. Suggerisco di premere "Invio" per ciascuna domanda per selezionare l'impostazione predefinita. 9bfa2d507e199c59.png
  2. Infine, dovrai configurare gli emulatori. Selezionare Firestore e Autenticazione dall'elenco, quindi premere "Invio" per ciascuna domanda sulle porte specifiche da utilizzare per ciascun emulatore. Dovresti selezionare l'impostazione predefinita, Sì, quando ti viene chiesto se desideri utilizzare l'interfaccia utente dell'emulatore.

Alla fine del processo, dovresti vedere un output simile allo screenshot seguente.

Importante : il tuo output potrebbe essere leggermente diverso dal mio, come mostrato nello screenshot qui sotto, perché la domanda finale verrà impostata su "No" per impostazione predefinita se hai già scaricato gli emulatori.

8544e41037637b07.png

Configura FlutterFire

Successivamente, puoi utilizzare FlutterFire per generare il codice Dart necessario per utilizzare Firebase nella tua app Flutter.

flutterfire configure

Quando esegui questo comando, ti verrà richiesto di selezionare quale progetto Firebase desideri utilizzare e quali piattaforme desideri configurare. In questo codelab, gli esempi utilizzano Flutter Web, ma puoi configurare il tuo progetto Firebase per utilizzare tutte le opzioni.

Le schermate seguenti mostrano le richieste a cui dovrai rispondere.

619b7aca6dc15472.png301c9534f594f472.png

Questa schermata mostra l'output alla fine del processo. Se hai familiarità con Firebase, noterai che non è stato necessario creare applicazioni nella console e la CLI di FlutterFire lo ha fatto per te.

12199a85ade30459.png

Aggiungi pacchetti Firebase all'app Flutter

Il passaggio finale della configurazione consiste nell'aggiungere i pacchetti Firebase pertinenti al tuo progetto Flutter. Nel terminale, assicurati di essere nella root del progetto Flutter su flutter-codelabs/firebase-emulator-suite/start . Quindi, esegui i tre comandi seguenti:

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

Questi sono gli unici pacchetti che utilizzerai in questa applicazione.

4. Abilitazione degli emulatori Firebase

Finora, l'app Flutter e il tuo progetto Firebase sono configurati per poter utilizzare gli emulatori, ma devi comunque indicare al codice Flutter di reindirizzare le richieste Firebase in uscita alle porte locali.

Innanzitutto, aggiungi il codice di inizializzazione Firebase e il codice di configurazione dell'emulatore alla funzione main in main.dart.

main.dart

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

import 'app_state.dart';
import 'firebase_options.dart';
import 'logged_in_view.dart';
import 'logged_out_view.dart';


void main() async {
 WidgetsFlutterBinding.ensureInitialized();
 await Firebase.initializeApp(
   options: DefaultFirebaseOptions.currentPlatform,
 );

 if (kDebugMode) {
   try {
     FirebaseFirestore.instance.useFirestoreEmulator('localhost', 8080);
     await FirebaseAuth.instance.useAuthEmulator('localhost', 9099);
   } catch (e) {
     // ignore: avoid_print
     print(e);
   }
 }

 runApp(MyApp());
}

Le prime righe di codice inizializzano Firebase. Quasi universalmente, se lavori con Firebase in un'app Flutter, puoi iniziare chiamando WidgetsFlutterBinding.ensureInitialized e Firebase.initializeApp .

Successivamente, il codice che inizia con la riga if (kDebugMode) indica alla tua app di scegliere come target gli emulatori anziché un progetto Firebase di produzione. kDebugMode garantisce che il targeting degli emulatori avvenga solo se ti trovi in ​​un ambiente di sviluppo. Poiché kDebugMode è un valore costante, il compilatore Dart sa come rimuovere completamente il blocco di codice in modalità di rilascio.

Avvia gli emulatori

Dovresti avviare gli emulatori prima di avviare l'app Flutter. Innanzitutto, avvia gli emulatori eseguendo questo nel terminale:

firebase emulators:start

Questo comando avvia gli emulatori ed espone le porte localhost con le quali possiamo interagire con loro. Quando esegui quel comando, dovresti vedere un output simile a questo:

bb7181eb70829606.png

Questo output ti dice quali emulatori sono in esecuzione e dove puoi andare per vedere gli emulatori. Innanzitutto, controlla l'interfaccia utente dell'emulatore su localhost:4000 .

11563f4c7216de81.png

Questa è la home page dell'interfaccia utente dell'emulatore locale. Elenca tutti gli emulatori disponibili e ciascuno è etichettato con lo stato attivato o disattivato.

5. L'emulatore di autenticazione Firebase

Il primo emulatore che utilizzerai è l'emulatore di autenticazione. Inizia con l'emulatore di autenticazione facendo clic su "Vai all'emulatore" sulla scheda di autenticazione nell'interfaccia utente e vedrai una pagina simile a questa:

3c1bfded40733189.png

Questa pagina presenta somiglianze con la pagina della console Web di autenticazione. Ha una tabella che elenca gli utenti come la console online e ti consente di aggiungere manualmente gli utenti. Una grande differenza qui è che l'unica opzione di metodo di autenticazione disponibile sugli emulatori è tramite e-mail e password. Ciò è sufficiente per lo sviluppo locale.

Successivamente, seguirai il processo di aggiunta di un utente all'emulatore di autenticazione Firebase e quindi l'accesso di tale utente tramite l'interfaccia utente di Flutter.

Aggiungi un utente

Fai clic sul pulsante "Aggiungi utente" e compila il modulo con queste informazioni:

  • Nome visualizzato: Dash
  • E-mail: dash@email.com
  • Parola d'ordine: dashword

Invia il modulo e vedrai che la tabella ora include un utente. Ora puoi aggiornare il codice per accedere con quell'utente.

logged_out_view.dart

L'unico codice nel widget LoggedOutView che deve essere aggiornato è nel callback che viene attivato quando un utente preme il pulsante di accesso. Aggiorna il codice in modo che assomigli a questo:

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

Il codice aggiornato sostituisce le stringhe TODO con l'e-mail e la password create nell'emulatore di autenticazione. E nella riga successiva, la riga if(true) è stata sostituita dal codice che controlla se state.user è null. Il codice in AppClass fa più luce su questo.

app_state.dart

È necessario aggiornare due parti del codice in AppState . Innanzitutto, assegna al membro della classe AppState.user il tipo User dal pacchetto firebase_auth , anziché il tipo Object .

In secondo luogo, compila il metodo AppState.login come mostrato di seguito:

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 definizione del tipo per l'utente ora è User? . La classe User proviene da Firebase Auth e fornisce le informazioni necessarie come User.displayName , di cui parleremo tra poco.

Questo è il codice di base necessario per accedere a un utente con un'e-mail e una password in Firebase Auth. Effettua una chiamata a FirebaseAuth per accedere, che restituisce un oggetto Future<UserCredential> . Al termine del future, questo codice controlla se è presente un User collegato a UserCredential . Se è presente un utente sull'oggetto credenziale, significa che un utente ha effettuato l'accesso correttamente ed è possibile impostare la proprietà AppState.user . Se non c'è, si è verificato un errore e viene stampato.

Tieni presente che l'unica riga di codice in questo metodo specifica per questa app (anziché il codice FirebaseAuth generale) è la chiamata al metodo _listenForEntries , che verrà trattato nel passaggio successivo.

TODO: Icona azione: ricarica l'app, quindi premi il pulsante Accedi quando viene visualizzato. Ciò fa sì che l'app acceda a una pagina che dice "Bentornato, persona!" in cima. L'autenticazione deve funzionare, poiché ti consente di accedere a questa pagina, ma è necessario apportare un aggiornamento minore a logged_in_view.dart per visualizzare il nome effettivo dell'utente.

logged_in_view.dart

Modifica la prima riga nel metodo 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(
 // ...

Ora, questa riga recupera displayName dalla proprietà User sull'oggetto AppState . Questo displayName è stato impostato nell'emulatore quando hai definito il tuo primo utente. La tua app ora dovrebbe visualizzare "Bentornato, Dash!" quando accedi, anziché TODO .

6. Leggi e scrivi i dati sull'emulatore Firestore

Innanzitutto, controlla l'emulatore Firestore. Nella home page dell'interfaccia utente dell'emulatore ( localhost:4000 ), fai clic su "Vai all'emulatore" sulla scheda Firestore. Dovrebbe sembrare come questo:

Emulatore:

791fce7dc137910a.png

Console Firebase:

e0dde9aea34af050.png

Se hai esperienza con Firestore, noterai che questa pagina è simile alla pagina Firestore della console Firebase. Ci sono alcune differenze notevoli, però.

  1. Puoi cancellare tutti i dati con il semplice tocco di un pulsante. Ciò sarebbe pericoloso con i dati di produzione, ma è utile per un'iterazione rapida! Se stai lavorando a un nuovo progetto e il tuo modello di dati cambia, è facile cancellarlo.
  2. C'è una scheda "Richieste". Questa scheda ti consente di guardare le richieste in arrivo effettuate a questo emulatore. Discuterò questa scheda più dettagliatamente tra poco.
  3. Non sono presenti schede per Regole, Indici o Utilizzo. Esiste uno strumento (discusso nella sezione successiva) che aiuta a scrivere le regole di sicurezza, ma non è possibile impostare regole di sicurezza per l'emulatore locale.

Per riassumere l'elenco, questa versione di Firestore fornisce più strumenti utili durante lo sviluppo e rimuove gli strumenti necessari nella produzione.

Scrivi a Firestore

Prima di discutere la scheda "Richieste" nell'emulatore, fai prima una richiesta. Ciò richiede aggiornamenti del codice. Inizia collegando il modulo nell'app per scrivere una nuova Entry di diario su Firestore.

Il flusso di alto livello per inviare una Entry è:

  1. L'utente compila il modulo e preme il pulsante Submit
  2. L'interfaccia utente chiama AppState.writeEntryToFirebase
  3. AppState.writeEntryToFirebase aggiunge una voce a Firebase

Nessuno del codice coinvolto nel passaggio 1 o 2 deve essere modificato. L'unico codice da aggiungere per il passaggio 3 verrà aggiunto nella classe AppState . Apporta la seguente modifica a 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,
   });
 }
 // ...
}

Il codice nel metodo writeEntryToFirebase acquisisce un riferimento alla raccolta chiamata "Entries" in Firestore. Aggiunge quindi una nuova voce, che deve essere di tipo Map<String, String> .

In questo caso, la raccolta "Entries" in Firestore non esisteva, quindi Firestore ne ha creata una.

Con il codice aggiunto, ricarica o riavvia l'app, accedi e vai alla visualizzazione EntryForm . Puoi compilare il modulo con qualsiasi Strings desideri. (Il campo Date accetterà qualsiasi stringa, poiché è stato semplificato per questo codelab. Non ha una convalida forte né si preoccupa in alcun modo degli oggetti DateTime .)

Premere Invia sul modulo. Non accadrà nulla nell'app, ma potrai vedere la tua nuova voce nell'interfaccia utente dell'emulatore.

La scheda Richieste nell'emulatore Firestore

Nell'interfaccia utente, vai all'emulatore Firestore e guarda la scheda "Dati". Dovresti vedere che ora c'è una raccolta nella radice del tuo database chiamata "Voci". Dovrebbe contenere un documento che contenga le stesse informazioni che hai inserito nel modulo.

a978fb34fb8a83da.png

Ciò conferma che AppState.writeEntryToFirestore ha funzionato e ora puoi esplorare ulteriormente la richiesta nella scheda Richieste. Fai clic su quella scheda adesso.

Richieste dell'emulatore Firestore

Qui dovresti vedere un elenco simile a questo:

f0b37f0341639035.png

Puoi fare clic su uno qualsiasi di questi elementi dell'elenco e visualizzare numerose informazioni utili. Fai clic sulla voce di elenco CREATE che corrisponde alla tua richiesta per creare una nuova voce del diario. Vedrai una nuova tabella simile a questa:

385d62152e99aad4.png

Come accennato, l'emulatore Firestore fornisce strumenti per sviluppare le regole di sicurezza della tua app. Questa visualizzazione mostra esattamente quale riga delle regole di sicurezza è stata superata da questa richiesta (o non è riuscita, se così fosse). In un'app più solida, le regole di sicurezza possono crescere e avere più controlli di autorizzazione. Questa vista viene utilizzata per facilitare la scrittura e il debug di tali regole di autorizzazione.

Fornisce inoltre un modo semplice per ispezionare ogni parte di questa richiesta, inclusi i metadati e i dati di autenticazione. Questi dati vengono utilizzati per scrivere regole di autorizzazione complesse.

Lettura da Firestore

Firestore utilizza la sincronizzazione dei dati per inviare i dati aggiornati ai dispositivi connessi. Nel codice Flutter puoi ascoltare (o iscriverti) a raccolte e documenti Firestore e il tuo codice riceverà una notifica ogni volta che i dati cambiano. In questa app, l'ascolto degli aggiornamenti Firestore viene eseguito con il metodo chiamato AppState._listenForEntries .

Questo codice funziona insieme a StreamController e Stream chiamati rispettivamente AppState._entriesStreamController e AppState.entries . Quel codice è già scritto, così come tutto il codice necessario nell'interfaccia utente per visualizzare i dati da Firestore.

Aggiorna il metodo _listenForEntries in modo che corrisponda al codice seguente:

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

Questo codice ascolta la raccolta "Entries" in Firestore. Quando Firestore notifica a questo client la presenza di nuovi dati, passa tali dati e il codice in _listenForEntries modifica tutti i suoi documenti secondari in un oggetto che la nostra app può utilizzare ( Entry ). Quindi, aggiunge quelle voci allo StreamController chiamato _entriesStreamController (che l'interfaccia utente è in ascolto). Questo codice è l'unico aggiornamento richiesto.

Infine, ricorda che il metodo AppState.logIn effettua una chiamata a _listenForEntries , che avvia il processo di ascolto dopo che un utente ha effettuato l'accesso.

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

Ora esegui l'app. Dovrebbe sembrare come questo:

b8a31c7a8900331.gif

7. Esporta e importa dati nell'emulatore

Gli emulatori Firebase supportano l'importazione e l'esportazione di dati. L'utilizzo delle importazioni e delle esportazioni ti consente di continuare lo sviluppo con gli stessi dati quando fai una pausa dallo sviluppo e poi riprendi. Puoi anche inviare file di dati a Git e gli altri sviluppatori con cui lavori avranno gli stessi dati con cui lavorare.

Esporta i dati dell'emulatore

Innanzitutto, esporta i dati dell'emulatore che già possiedi. Mentre gli emulatori sono ancora in esecuzione, apri una nuova finestra di terminale e inserisci il seguente comando:

firebase emulators:export ./emulators_data

.emulators_data è un argomento che indica a Firebase dove esportare i dati. Se la directory non esiste, viene creata. Puoi utilizzare qualsiasi nome desideri per quella directory.

Quando esegui questo comando, vedrai questo output nel terminale in cui hai eseguito il 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

E se passi alla finestra del terminale in cui sono in esecuzione gli emulatori, vedrai questo output:

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

Infine, se guardi nella directory del tuo progetto, dovresti vedere una directory chiamata ./emulators_data , che contiene file JSON , tra gli altri file di metadati, con i dati che hai salvato.

Importa i dati dell'emulatore

Ora puoi importare tali dati come parte del tuo flusso di lavoro di sviluppo e iniziare da dove avevi interrotto.

Innanzitutto, interrompi gli emulatori se sono in esecuzione premendo CTRL+C nel terminale.

Successivamente, esegui il comando emulators:start che hai già visto, ma con un flag che indica quali dati importare:

firebase emulators:start --import ./emulators_data

Quando gli emulatori sono attivi, vai all'interfaccia utente dell'emulatore su localhost:4000 e dovresti vedere gli stessi dati con cui stavi lavorando in precedenza.

Esporta i dati automaticamente alla chiusura degli emulatori

Puoi anche esportare i dati automaticamente quando chiudi gli emulatori, invece di ricordarti di esportare i dati alla fine di ogni sessione di sviluppo.

Quando avvii i tuoi emulatori, esegui il comando emulators:start con due flag aggiuntivi.

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

Ecco! I tuoi dati verranno ora salvati e ricaricati ogni volta che lavorerai con gli emulatori per questo progetto. Puoi anche specificare una directory diversa come argomento per il –export-on-exit flag , ma per impostazione predefinita verrà utilizzata la directory passata a –import .

Puoi anche utilizzare qualsiasi combinazione di queste opzioni. Questa è la nota dai documenti : la directory di esportazione può essere specificata con questo flag: firebase emulators:start --export-on-exit=./saved-data . Se viene utilizzato --import , il percorso di esportazione predefinito è lo stesso; ad esempio: firebase emulators:start --import=./data-path --export-on-exit . Infine, se lo si desidera, passare percorsi di directory diversi ai flag --import e --export-on-exit .

8. Congratulazioni!

Hai completato Diventa operativo con l'emulatore Firebase e Flutter. Puoi trovare il codice completo per questo Codelab nella directory "complete" su github: Flutter Codelabs

Di cosa abbiamo parlato

  • Configurazione di un'app Flutter per utilizzare Firebase
  • Configurazione di un progetto Firebase
  • CLI di FlutterFire
  • CLI di Firebase
  • Emulatore di autenticazione Firebase
  • Emulatore Firebase Firestore
  • Importazione ed esportazione dei dati dell'emulatore

Prossimi passi

Saperne di più

Sparky è orgoglioso di te!

2a0ad195769368b1.gif