Lokalny rozwój aplikacji Flutter przy użyciu pakietu Firebase Emulator Suite

1. Zanim zaczniesz

Podczas tych zajęć z programowania dowiesz się, jak używać pakietu emulatorów Firebase z Flutterem podczas programowania lokalnego. Dowiesz się, jak korzystać z uwierzytelniania za pomocą hasła e-mail za pośrednictwem pakietu Emulator Suite oraz jak odczytywać i zapisywać dane w emulatorze Firestore. Na koniec będziesz importować i eksportować dane z emulatorów, aby pracować z tymi samymi sfałszowanymi danymi za każdym razem, gdy wrócisz do programowania.

Warunki wstępne

W tym ćwiczeniu z programowania założono, że masz pewne doświadczenie z Flutterem. Jeśli nie, może najpierw naucz się podstaw. Pomocne są następujące linki:

Powinieneś także mieć pewne doświadczenie z Firebase, ale nie ma problemu, jeśli nigdy nie dodałeś Firebase do projektu Flutter. Jeśli nie znasz konsoli Firebase lub jesteś całkowicie nowy w Firebase, najpierw zapoznaj się z poniższymi linkami:

Co stworzysz

To ćwiczenie z programowania przeprowadzi Cię przez proces tworzenia prostej aplikacji do tworzenia dziennika. Aplikacja będzie posiadała ekran logowania, a także ekran umożliwiający odczytywanie poprzednich wpisów w dzienniku oraz tworzenie nowych.

cd5c4753bbee8af.png8cb4d21f656540bf.png

Czego się dowiesz

Dowiesz się, jak rozpocząć korzystanie z Firebase oraz jak zintegrować i używać pakietu Firebase Emulator z przepływem pracy programistycznej Flutter. Omówione zostaną następujące tematy dotyczące Firebase:

Należy pamiętać, że te tematy zostały omówione w zakresie, w jakim są wymagane do omówienia pakietu emulatorów Firebase. To ćwiczenie z programowania koncentruje się na dodawaniu projektu Firebase do aplikacji Flutter i programowaniu przy użyciu pakietu Firebase Emulator Suite. Nie będzie szczegółowych dyskusji na temat uwierzytelniania Firebase ani Firestore. Jeśli nie jesteś zaznajomiony z tymi tematami, zalecamy rozpoczęcie od ćwiczenia z programowania Poznajemy Firebase dla Flutter .

Co będziesz potrzebował

  • Praktyczna znajomość Fluttera i zainstalowanego pakietu SDK
  • Edytory tekstu Intellij JetBrains lub VS Code
  • Przeglądarka Google Chrome (lub inny preferowany cel programistyczny Fluttera. Niektóre polecenia terminala w tym ćwiczeniu zakładają, że uruchamiasz aplikację w przeglądarce Chrome)

2. Utwórz i skonfiguruj projekt Firebase

Pierwszym zadaniem, które musisz wykonać, jest utworzenie projektu Firebase w konsoli internetowej Firebase. Zdecydowana większość tych ćwiczeń z programowania skupi się na pakiecie emulatorów, który korzysta z lokalnie działającego interfejsu użytkownika, ale najpierw musisz skonfigurować pełny projekt Firebase.

Utwórz projekt Firebase

  1. Zaloguj się do konsoli Firebase.
  2. W konsoli Firebase kliknij Dodaj projekt (lub Utwórz projekt ) i wprowadź nazwę swojego projektu Firebase (na przykład „ Firebase-Flutter-Codelab”) .

fe6aeab3b91965ed.png

  1. Kliknij opcje tworzenia projektu. Jeśli pojawi się monit, zaakceptuj warunki Firebase. Pomiń konfigurowanie Google Analytics, ponieważ nie będziesz używać Analytics w tej aplikacji.

d1fcec48bf251eaa.png

Aby dowiedzieć się więcej o projektach Firebase, zobacz Omówienie projektów Firebase .

Tworzona aplikacja korzysta z dwóch produktów Firebase dostępnych dla aplikacji Flutter:

  • Uwierzytelnianie Firebase , aby umożliwić użytkownikom logowanie się do Twojej aplikacji.
  • Cloud Firestore do zapisywania uporządkowanych danych w chmurze i otrzymywania natychmiastowych powiadomień o zmianach danych.

Te dwa produkty wymagają specjalnej konfiguracji lub należy je włączyć za pomocą konsoli Firebase.

Włącz Cloud Firestore

Aplikacja Flutter korzysta z Cloud Firestore do zapisywania wpisów w dzienniku.

Włącz Cloud Firestore:

  1. W sekcji Kompilacja konsoli Firebase kliknij Cloud Firestore .
  2. Kliknij opcję Utwórz bazę danych . 99e8429832d23fa3.png
  3. Wybierz opcję Uruchom w trybie testowym . Przeczytaj zastrzeżenie dotyczące zasad bezpieczeństwa. Tryb testowy zapewnia możliwość swobodnego zapisu do bazy danych podczas programowania. Kliknij Następny . 6be00e26c72ea032.png
  4. Wybierz lokalizację swojej bazy danych (możesz po prostu użyć lokalizacji domyślnej). Pamiętaj, że tej lokalizacji nie można później zmienić. 278656eefcfb0216.png
  5. Kliknij opcję Włącz .

3. Skonfiguruj aplikację Flutter

Zanim zaczniemy, musisz pobrać kod startowy i zainstalować interfejs CLI Firebase.

Zdobądź kod startowy

Sklonuj repozytorium GitHub z wiersza poleceń:

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

Alternatywnie, jeśli masz zainstalowane narzędzie cli GitHuba :

gh repo clone flutter/codelabs flutter-codelabs

Przykładowy kod należy sklonować do katalogu flutter-codelabs , który zawiera kod kolekcji codelabs. Kod tego ćwiczenia z kodowania znajduje się w flutter-codelabs/firebase-emulator-suite .

Struktura katalogów w flutter-codelabs/firebase-emulator-suite to dwa projekty Flutter. Jeden z nich nazywa się complete i możesz się do niego odwołać, jeśli chcesz przejść dalej lub odwołać się do własnego kodu. Drugi projekt nazywa się start .

Kod, od którego chcesz zacząć, znajduje się w katalogu flutter-codelabs/firebase-emulator-suite/start . Otwórz lub zaimportuj ten katalog do preferowanego IDE.

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

Zainstaluj interfejs wiersza polecenia Firebase

Interfejs Firebase CLI udostępnia narzędzia do zarządzania projektami Firebase. Do korzystania z pakietu emulatorów wymagany jest interfejs CLI, dlatego należy go zainstalować.

Istnieje wiele sposobów instalacji interfejsu CLI. Najprostszym sposobem, jeśli używasz systemu MacOS lub Linux, jest uruchomienie tego polecenia na terminalu:

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

Po zainstalowaniu interfejsu CLI musisz uwierzytelnić się w Firebase.

  1. Zaloguj się do Firebase przy użyciu swojego konta Google, uruchamiając następujące polecenie:
firebase login
  1. To polecenie łączy komputer lokalny z Firebase i zapewnia dostęp do projektów Firebase.
  1. Sprawdź, czy interfejs CLI jest poprawnie zainstalowany i ma dostęp do Twojego konta, wyświetlając listę projektów Firebase. Uruchom następujące polecenie:
firebase projects:list
  1. Wyświetlana lista powinna być taka sama, jak projekty Firebase wymienione w konsoli Firebase . Powinieneś zobaczyć przynajmniej firebase-flutter-codelab.

Zainstaluj interfejs wiersza polecenia FlutterFire

Interfejs CLI FlutterFire jest oparty na interfejsie CLI Firebase i ułatwia integrację projektu Firebase z aplikacją Flutter.

Najpierw zainstaluj CLI:

dart pub global activate flutterfire_cli

Upewnij się, że interfejs CLI został zainstalowany. Uruchom następujące polecenie w katalogu projektu Flutter i upewnij się, że interfejs CLI wyświetla menu pomocy.

flutterfire --help

Użyj Firebase CLI i FlutterFire CLI, aby dodać projekt Firebase do aplikacji Flutter

Po zainstalowaniu dwóch interfejsów CLI możesz skonfigurować indywidualne produkty Firebase (takie jak Firestore), pobrać emulatory i dodać Firebase do aplikacji Flutter za pomocą zaledwie kilku poleceń terminala.

Najpierw zakończ konfigurację Firebase, uruchamiając następujące polecenie:

firebase init

To polecenie poprowadzi Cię przez serię pytań potrzebnych do skonfigurowania projektu. Te zrzuty ekranu pokazują przepływ:

  1. Po wyświetleniu monitu o wybranie funkcji wybierz „Firestore” i „Emulatory”. (Nie ma opcji uwierzytelniania, ponieważ nie korzysta ona z konfiguracji, którą można modyfikować na podstawie plików projektu Flutter.) fe6401d769be8f53.png
  2. Następnie po wyświetleniu monitu wybierz opcję „Użyj istniejącego projektu”.

f11dcab439e6ac1e.png

  1. Teraz wybierz projekt utworzony w poprzednim kroku: flutter-firebase-codelab.

3bdc0c6934991c25.png

  1. Następnie zostaniesz poproszony o serię pytań dotyczących nazewnictwa plików, które zostaną wygenerowane. Sugeruję naciśnięcie „Enter” przy każdym pytaniu, aby wybrać ustawienie domyślne. 9bfa2d507e199c59.png
  2. Na koniec musisz skonfigurować emulatory. Wybierz z listy Firestore i uwierzytelnianie, a następnie naciśnij „Enter” przy każdym pytaniu dotyczącym konkretnych portów, których należy używać dla każdego emulatora. Na pytanie, czy chcesz używać interfejsu emulatora, powinieneś wybrać opcję domyślną Tak.

Na koniec procesu powinieneś zobaczyć wynik, który wygląda jak na poniższym zrzucie ekranu.

Ważne : Twoje dane wyjściowe mogą nieznacznie różnić się od moich, jak widać na zrzucie ekranu poniżej, ponieważ ostatnie pytanie będzie domyślnie brzmiało „Nie”, jeśli masz już pobrane emulatory.

8544e41037637b07.png

Skonfiguruj FlutterFire

Następnie możesz użyć FlutterFire do wygenerowania kodu Dart potrzebnego do korzystania z Firebase w aplikacji Flutter.

flutterfire configure

Po uruchomieniu tego polecenia zostaniesz poproszony o wybranie projektu Firebase, którego chcesz używać i platform, które chcesz skonfigurować. W tych ćwiczeniach z programowania przykłady wykorzystują Flutter Web, ale możesz skonfigurować swój projekt Firebase tak, aby korzystał ze wszystkich opcji.

Poniższe zrzuty ekranu przedstawiają monity, na które należy odpowiedzieć.

619b7aca6dc15472.png301c9534f594f472.png

Ten zrzut ekranu przedstawia wynik na końcu procesu. Jeśli znasz Firebase, zauważysz, że nie musisz tworzyć aplikacji w konsoli, a CLI FlutterFire zrobiło to za Ciebie.

12199a85ade30459.png

Dodaj pakiety Firebase do aplikacji Flutter

Ostatnim krokiem konfiguracji jest dodanie odpowiednich pakietów Firebase do projektu Flutter. W terminalu upewnij się, że jesteś w katalogu głównym projektu Flutter pod adresem flutter-codelabs/firebase-emulator-suite/start . Następnie uruchom trzy następujące polecenia:

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

To jedyne pakiety, których będziesz używać w tej aplikacji.

4. Włączanie emulatorów Firebase

Jak dotąd aplikacja Flutter i projekt Firebase są skonfigurowane tak, aby mogły korzystać z emulatorów, ale nadal musisz poinformować kod Flutter, aby przekierowywał wychodzące żądania Firebase do portów lokalnych.

Najpierw dodaj kod inicjujący Firebase i kod konfiguracyjny emulatora do main funkcji w main.dart.

główna.rzutka

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

Pierwsze kilka wierszy kodu inicjuje Firebase. Niemal powszechnie, jeśli pracujesz z Firebase w aplikacji Flutter, chcesz zacząć od wywołania WidgetsFlutterBinding.ensureInitialized i Firebase.initializeApp .

Następnie kod zaczynający się od wiersza if (kDebugMode) informuje aplikację, aby kierowała reklamy na emulatory, a nie na produkcyjny projekt Firebase. kDebugMode zapewnia, że ​​celowanie w emulatory będzie miało miejsce tylko w środowisku programistycznym. Ponieważ kDebugMode jest wartością stałą, kompilator Dart wie, że w trybie wydania należy całkowicie usunąć ten blok kodu.

Uruchom emulatory

Powinieneś uruchomić emulatory przed uruchomieniem aplikacji Flutter. Najpierw uruchom emulatory, uruchamiając to w terminalu:

firebase emulators:start

To polecenie uruchamia emulatory i udostępnia porty hosta lokalnego, z którymi możemy z nimi współdziałać. Po uruchomieniu tego polecenia powinieneś zobaczyć dane wyjściowe podobne do tych:

bb7181eb70829606.png

To wyjście informuje, które emulatory są uruchomione i gdzie można je zobaczyć. Najpierw sprawdź interfejs emulatora na localhost:4000 .

11563f4c7216de81.png

To jest strona główna interfejsu użytkownika lokalnego emulatora. Zawiera listę wszystkich dostępnych emulatorów, a każdy z nich jest oznaczony jako włączony lub wyłączony.

5. Emulator uwierzytelniania Firebase

Pierwszym emulatorem, którego będziesz używać, jest emulator uwierzytelniania. Zacznij od emulatora uwierzytelniania, klikając „Przejdź do emulatora” na karcie Uwierzytelnianie w interfejsie użytkownika, a zobaczysz stronę wyglądającą tak:

3c1bfded40733189.png

Ta strona jest podobna do strony konsoli internetowej Auth. Zawiera tabelę zawierającą listę użytkowników, takich jak konsola online, i umożliwia ręczne dodawanie użytkowników. Jedną dużą różnicą jest to, że jedyną opcją metody uwierzytelniania dostępną w emulatorach jest e-mail i hasło. To wystarczy do rozwoju lokalnego.

Następnie przejdziesz przez proces dodawania użytkownika do emulatora Firebase Auth, a następnie logowania tego użytkownika za pomocą interfejsu użytkownika Flutter.

Dodaj użytkownika

Kliknij przycisk „Dodaj użytkownika” i wypełnij formularz następującymi informacjami:

  • Nazwa wyświetlana: Dash
  • E-mail: dash@email.com
  • Hasło: myślnik

Prześlij formularz, a zobaczysz, że tabela zawiera teraz użytkownika. Teraz możesz zaktualizować kod, aby zalogować się z tym użytkownikiem.

zalogowany_out_view.dart

Jedyny kod w widgecie LoggedOutView , który wymaga aktualizacji, znajduje się w wywołaniu zwrotnym wyzwalanym, gdy użytkownik naciśnie przycisk logowania. Zaktualizuj kod, aby wyglądał następująco:

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

Zaktualizowany kod zastępuje ciągi TODO adresem e-mail i hasłem utworzonym w emulatorze autoryzacji. W kolejnym wierszu wiersz if(true) został zastąpiony kodem sprawdzającym, czy state.user ma wartość null. Więcej światła na ten temat rzuca kod w AppClass .

stan_aplikacji.dart

Należy zaktualizować dwie części kodu w AppState . Najpierw nadaj członkowi klasy AppState.user typ User z pakietu firebase_auth , a nie typ Object .

Po drugie, wypełnij metodę AppState.login , jak pokazano poniżej:

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

Definicja typu użytkownika to teraz User? . Ta klasa User pochodzi z Firebase Auth i dostarcza potrzebnych informacji, takich jak User.displayName , które zostaną omówione za chwilę.

Jest to podstawowy kod potrzebny do zalogowania użytkownika za pomocą adresu e-mail i hasła w Firebase Auth. Wywołuje FirebaseAuth w celu zalogowania się, co zwraca obiekt Future<UserCredential> . Kiedy przyszłość dobiegnie końca, ten kod sprawdza, czy istnieje User dołączony do UserCredential . Jeśli w obiekcie referencji znajduje się użytkownik, oznacza to, że użytkownik pomyślnie się zalogował i można ustawić właściwość AppState.user . Jeśli nie, oznacza to, że wystąpił błąd i zostanie on wydrukowany.

Należy pamiętać, że jedynym wierszem kodu w tej metodzie, który jest specyficzny dla tej aplikacji (a nie ogólnym kodem FirebaseAuth), jest wywołanie metody _listenForEntries , co zostanie omówione w następnym kroku.

DO ZROBIENIA: Ikona akcji – Załaduj ponownie aplikację, a następnie naciśnij przycisk Zaloguj się po jej renderowaniu. Spowoduje to przejście aplikacji do strony z informacją „Witamy ponownie, osobo!” na górze. Uwierzytelnianie musi działać, ponieważ umożliwia nawigację do tej strony, ale należy wprowadzić niewielką aktualizację logged_in_view.dart , aby wyświetlić rzeczywistą nazwę użytkownika.

zalogowany_w_widoku.dart

Zmień pierwszą linię w metodzie 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(
 // ...

Teraz ta linia pobiera displayName z właściwości User obiektu AppState . Ta displayName została ustawiona w emulatorze podczas definiowania pierwszego użytkownika. Twoja aplikacja powinna teraz wyświetlać komunikat „Witamy ponownie, Dash!” podczas logowania, a nie TODO .

6. Odczytuj i zapisuj dane w emulatorze Firestore

Najpierw sprawdź emulator Firestore. Na stronie głównej interfejsu użytkownika emulatora ( localhost:4000 ) kliknij „Przejdź do emulatora” na karcie Firestore. To powinno wyglądać tak:

Emulator:

791fce7dc137910a.png

Konsola Firebase:

e0dde9aea34af050.png

Jeśli masz jakieś doświadczenie z Firestore, zauważysz, że ta strona wygląda podobnie do strony Firestore w konsoli Firebase. Istnieje jednak kilka znaczących różnic.

  1. Możesz wyczyścić wszystkie dane jednym dotknięciem. Byłoby to niebezpieczne w przypadku danych produkcyjnych, ale jest pomocne przy szybkiej iteracji! Jeśli pracujesz nad nowym projektem i Twój model danych ulegnie zmianie, łatwo go wyczyścić.
  2. Istnieje zakładka „Żądania”. Ta zakładka umożliwia przeglądanie żądań przychodzących wysyłanych do tego emulatora. Tę zakładkę omówię bardziej szczegółowo za chwilę.
  3. Nie ma zakładek Reguły, Indeksy i Użycie. Istnieje narzędzie (omówione w następnej sekcji), które pomaga pisać reguły bezpieczeństwa, ale nie można ustawić reguł bezpieczeństwa dla lokalnego emulatora.

Podsumowując tę ​​listę, ta wersja Firestore zapewnia więcej narzędzi przydatnych podczas programowania i usuwa narzędzia potrzebne w produkcji.

Napisz do Firestore

Zanim omówisz zakładkę „Żądania” w emulatorze, najpierw złóż żądanie. Wymaga to aktualizacji kodu. Zacznij od podłączenia formularza w aplikacji, aby napisać nowy dziennik Entry to Firestore.

Ogólny proces przesyłania Entry jest następujący:

  1. Użytkownik wypełnia formularz i naciska przycisk Submit
  2. Interfejs użytkownika wywołuje AppState.writeEntryToFirebase
  3. AppState.writeEntryToFirebase dodaje wpis do Firebase

Żaden z kodu użytego w kroku 1 lub 2 nie wymaga zmiany. Jedyny kod, który należy dodać w kroku 3, zostanie dodany w klasie AppState . Wprowadź następującą zmianę w AppState.writeEntryToFirebase .

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

Kod w metodzie writeEntryToFirebase pobiera odwołanie do kolekcji o nazwie „Wpisy” w Firestore. Następnie dodaje nowy wpis, który musi być typu Map<String, String> .

W tym przypadku kolekcja „Wpisy” w Firestore nie istniała, więc Firestore ją utworzył.

Po dodaniu tego kodu załaduj ponownie lub uruchom ponownie aplikację, zaloguj się i przejdź do widoku EntryForm . Możesz wypełnić formularz dowolnymi Strings . (Pole Date przyjmie dowolny ciąg znaków, ponieważ zostało uproszczone na potrzeby tego ćwiczenia z kodowania. Nie wymaga ono silnej weryfikacji ani w żaden sposób nie przejmuje się obiektami DateTime ).

Naciśnij przycisk Wyślij w formularzu. Nic się nie stanie w aplikacji, ale możesz zobaczyć nowy wpis w interfejsie emulatora.

Karta żądań w emulatorze Firestore

W interfejsie użytkownika przejdź do emulatora Firestore i spójrz na kartę „Dane”. Powinieneś zobaczyć, że w katalogu głównym Twojej bazy danych znajduje się teraz kolekcja o nazwie „Wpisy”. Powinien zawierać dokument zawierający te same informacje, które wpisałeś w formularzu.

a978fb34fb8a83da.png

Potwierdza to, że AppState.writeEntryToFirestore zadziałało i teraz możesz dokładniej zbadać żądanie na karcie Żądania. Kliknij tę kartę teraz.

Żądania emulatora Firestore

Tutaj powinieneś zobaczyć listę wyglądającą podobnie do tej:

f0b37f0341639035.png

Możesz kliknąć dowolny z tych elementów listy i wyświetlić sporo przydatnych informacji. Kliknij pozycję CREATE odpowiadającą Twojemu żądaniu utworzenia nowego wpisu księgowego. Zobaczysz nową tabelę, która wygląda tak:

385d62152e99aad4.png

Jak wspomniano, emulator Firestore zapewnia narzędzia do opracowywania reguł bezpieczeństwa aplikacji. Ten widok pokazuje dokładnie, którą linię reguł bezpieczeństwa przeszło to żądanie (lub nie, jeśli tak było). W bardziej niezawodnej aplikacji reguły bezpieczeństwa mogą się rozwijać i mieć wiele kontroli autoryzacji. Ten widok ułatwia pisanie i debugowanie reguł autoryzacji.

Zapewnia także łatwy sposób sprawdzenia każdej części tego żądania, w tym metadanych i danych uwierzytelniających. Dane te służą do pisania skomplikowanych reguł autoryzacji.

Czytanie z Firestore

Firestore wykorzystuje synchronizację danych do przesyłania zaktualizowanych danych do podłączonych urządzeń. W kodzie Flutter możesz słuchać (lub subskrybować) kolekcji i dokumentów Firestore, a Twój kod będzie powiadamiany o każdej zmianie danych. W tej aplikacji nasłuchiwanie aktualizacji Firestore odbywa się za pomocą metody o nazwie AppState._listenForEntries .

Ten kod działa w połączeniu z StreamController i Stream o nazwie odpowiednio AppState._entriesStreamController i AppState.entries . Ten kod jest już napisany, podobnie jak cały kod potrzebny w interfejsie użytkownika do wyświetlania danych z Firestore.

Zaktualizuj metodę _listenForEntries , aby odpowiadała poniższemu kodowi:

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

Ten kod nasłuchuje kolekcji „Wpisy” w Firestore. Kiedy Firestore powiadamia tego klienta o nowych danych, przekazuje je, a kod w _listenForEntries zmienia wszystkie dokumenty podrzędne w obiekt, z którego może korzystać nasza aplikacja ( Entry ). Następnie dodaje te wpisy do StreamController o nazwie _entriesStreamController (którego nasłuchuje interfejs użytkownika). Ten kod jest jedyną wymaganą aktualizacją.

Na koniec pamiętaj, że metoda AppState.logIn wywołuje metodę _listenForEntries , która rozpoczyna proces nasłuchiwania po zalogowaniu się użytkownika.

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

Teraz uruchom aplikację. To powinno wyglądać tak:

b8a31c7a8900331.gif

7. Eksportuj i importuj dane do emulatora

Emulatory Firebase obsługują importowanie i eksportowanie danych. Korzystanie z importu i eksportu pozwala kontynuować programowanie z tymi samymi danymi, gdy zrobisz sobie przerwę w programowaniu, a następnie wznowisz. Możesz także przekazać pliki danych do git, a inni programiści, z którymi współpracujesz, będą mieli te same dane do pracy.

Eksportuj dane emulatora

Najpierw wyeksportuj dane emulatora, które już posiadasz. Gdy emulatory nadal działają, otwórz nowe okno terminala i wprowadź następujące polecenie:

firebase emulators:export ./emulators_data

.emulators_data to argument, który mówi Firebase, gdzie ma wyeksportować dane. Jeśli katalog nie istnieje, zostanie utworzony. Możesz użyć dowolnej nazwy tego katalogu.

Po uruchomieniu tego polecenia zobaczysz następujące dane wyjściowe w terminalu, w którym uruchomiłeś polecenie:

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

A jeśli przełączysz się do okna terminala, w którym działają emulatory, zobaczysz następujące dane wyjściowe:

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

I na koniec, jeśli zajrzysz do katalogu swojego projektu, powinieneś zobaczyć katalog o nazwie ./emulators_data , który zawiera między innymi pliki JSON z zapisanymi danymi.

Importuj dane emulatora

Teraz możesz zaimportować te dane w ramach procesu programowania i rozpocząć od miejsca, w którym przerwałeś.

Najpierw zatrzymaj emulatory, jeśli działają, naciskając CTRL+C w terminalu.

Następnie uruchom polecenie emulators:start , które już widziałeś, ale z flagą informującą, jakie dane zaimportować:

firebase emulators:start --import ./emulators_data

Gdy emulatory zostaną uruchomione, przejdź do interfejsu użytkownika emulatora pod localhost:4000 i powinieneś zobaczyć te same dane, z którymi pracowałeś wcześniej.

Eksportuj dane automatycznie przy zamykaniu emulatorów

Możesz także eksportować dane automatycznie po zamknięciu emulatorów, zamiast pamiętać o eksportowaniu danych na koniec każdej sesji programistycznej.

Po uruchomieniu emulatorów uruchom polecenie emulators:start z dwiema dodatkowymi flagami.

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

Voila! Twoje dane będą teraz zapisywane i ładowane ponownie za każdym razem, gdy będziesz pracować z emulatorami dla tego projektu. Możesz także określić inny katalog jako argument –export-on-exit flag , ale domyślnie będzie to katalog przekazany do –import .

Możesz także użyć dowolnej kombinacji tych opcji. Oto uwaga z dokumentów : Katalog eksportu można określić za pomocą tej flagi: firebase emulators:start --export-on-exit=./saved-data . Jeśli zostanie użyte --import , domyślna ścieżka eksportu będzie taka sama; na przykład: firebase emulators:start --import=./data-path --export-on-exit . Na koniec, jeśli chcesz, przekaż różne ścieżki katalogów do flag --import i --export-on-exit .

8. Gratulacje!

Ukończyłeś konfigurację i działanie z emulatorem Firebase i Flutterem. Ukończony kod tego Codelaba znajdziesz w katalogu „complete” na githubie: Flutter Codelabs

Co omówiliśmy

  • Konfigurowanie aplikacji Flutter do korzystania z Firebase
  • Konfigurowanie projektu Firebase
  • Interfejs FlutterFire
  • Interfejs wiersza polecenia Firebase
  • Emulator uwierzytelniania Firebase
  • Emulator Firebase Firestore
  • Importowanie i eksportowanie danych emulatora

Następne kroki

Ucz się więcej

Sparky jest z Ciebie dumny!

2a0ad195769368b1.gif