Lokalne programowanie aplikacji Flutter z użyciem Pakietu emulatorów Firebase

1. Zanim zaczniesz

Z tego ćwiczenia w Codelabs dowiesz się, jak korzystać z Pakietu emulatorów Firebase w technologii Flutter podczas lokalnego programowania. Dowiesz się, jak korzystać z uwierzytelniania przez e-maila za pomocą hasła w Pakietie emulatorów oraz jak odczytywać i zapisywać dane w emulatorze Firestore. Na koniec będziesz importować i eksportować dane z emulatorów, aby używać tych samych fałszywych danych za każdym razem, gdy wrócisz do programowania.

Wymagania wstępne

W tym ćwiczeniu w programowaniu zakładamy, że masz już doświadczenie w korzystaniu z platformy Flutter. Jeśli nie, warto najpierw poznać podstawy. Przydatne będą te linki:

Znasz też podstawy Firebase, ale nie musisz dodawać Firebase do projektu Flutter. Jeśli nie znasz jeszcze konsoli Firebase lub dopiero zaczynasz korzystać z Firebase, zapoznaj się najpierw z tymi linkami:

Co utworzysz

Dzięki temu ćwiczeniu w Codelabs dowiesz się, jak utworzyć prostą aplikację do obsługi dziennika. W aplikacji będzie widoczny ekran logowania oraz ekran, na którym można będzie odczytywać wcześniejsze wpisy do dziennika i tworzyć nowe.

cd5c4753bbee8af.png 8cb4d21f656540bf.png

Czego się nauczysz

Dowiesz się, jak zacząć korzystać z Firebase oraz jak zintegrować pakiet emulatorów Firebase i korzystać z niego w procesie programowania Flutter. Poruszymy te tematy związane z Firebase:

Pamiętaj, że te tematy są uwzględnione w zakresie, w jakim są wymagane do obsługi pakietu emulatorów Firebase. Skupia się on na dodawaniu projektu Firebase do aplikacji Flutter i programowaniu za pomocą Pakietu emulatorów Firebase. Nie będziemy omawiać szczegółowo funkcji Uwierzytelnianie Firebase ani Firestore. Jeśli nie znasz tych zagadnień, zalecamy zapoznać się z ćwiczeniami z programowania zawierającymi informacje o Firebase i Flutter (w języku angielskim).

Czego potrzebujesz

  • praktyczna wiedza na temat technologii Flutter i zainstalowanego pakietu SDK.
  • Intellij JetBrains lub edytory tekstu VS Code
  • przeglądarki Google Chrome (lub innego preferowanego środowiska programistycznego w aplikacji Flutter, niektóre polecenia terminala w tym ćwiczeniu z programowania zakładają, że używasz aplikacji w Chrome).

2. Tworzenie i konfigurowanie projektu Firebase

Najpierw musisz utworzyć projekt Firebase w konsoli internetowej Firebase. Zdecydowana większość tych ćwiczeń w programie będzie dotyczyła Pakietu emulatorów, który wykorzystuje lokalnie działający interfejs użytkownika. Najpierw jednak musisz skonfigurować pełny projekt Firebase.

Tworzenie projektu Firebase

  1. Zaloguj się w konsoli Firebase.
  2. W konsoli Firebase kliknij Dodaj projekt (lub Utwórz projekt) i wpisz nazwę projektu Firebase (np. „Firebase-Flutter-Codelab”).

fe6aeab3b91965ed.png

  1. Klikaj opcje tworzenia projektów. Zaakceptuj warunki korzystania z Firebase, jeśli pojawi się taka prośba. Pomiń konfigurowanie Google Analytics, ponieważ nie będziesz korzystać z Analytics w tej aplikacji.

d1fcec48bf251eaa.png

Więcej informacji o projektach Firebase znajdziesz w artykule Omówienie projektów Firebase.

Tworzona aplikacja korzysta z 2 usług Firebase, które są dostępne dla aplikacji Flutter:

  • Uwierzytelnianie Firebase, które umożliwia użytkownikom logowanie się w aplikacji.
  • Cloud Firestore pozwala zapisywać uporządkowane dane w chmurze i otrzymywać natychmiastowe powiadomienia o zmianach danych.

Te 2 usługi wymagają specjalnej konfiguracji lub trzeba włączyć je w konsoli Firebase.

Włączanie Cloud Firestore

Aplikacja Flutter zapisuje wpisy do dziennika za pomocą Cloud Firestore.

Włącz Cloud Firestore:

  1. W sekcji Kompilacja konsoli Firebase kliknij Cloud Firestore.
  2. Kliknij Utwórz bazę danych. 99e8429832d23fa3.png
  3. Kliknij opcję Rozpocznij w trybie testowym. Przeczytaj wyłączenie odpowiedzialności dotyczące reguł zabezpieczeń. Tryb testowy umożliwia swobodne zapisywanie w bazie danych podczas programowania. Kliknij Dalej. 6be00e26c72ea032.png
  4. Wybierz lokalizację bazy danych (możesz tylko użyć domyślnej). Pamiętaj, że tej lokalizacji nie można później zmienić. 278656eefcfb0216.png
  5. Kliknij Włącz.

3. Konfigurowanie aplikacji Flutter

Zanim zaczniemy, musisz pobrać kod startowy i zainstalować interfejs wiersza poleceń Firebase.

Pobierz kod startowy

Skopiuj repozytorium GitHub, korzystając z wiersza poleceń:

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

Jeśli masz zainstalowane narzędzie interfejsu wiersza poleceń GitHub:

gh repo clone flutter/codelabs flutter-codelabs

Przykładowy kod należy skopiować do katalogu flutter-codelabs, który zawiera kod kolekcji ćwiczeń z programowania. Kod do tego ćwiczenia w Codelabs jest dostępny w języku flutter-codelabs/firebase-emulator-suite.

Struktura katalogów w flutter-codelabs/firebase-emulator-suite składa się z 2 projektów Flutter. Jeden z nich nosi nazwę complete. Możesz go użyć, aby przejść dalej lub znaleźć powiązanie z własnym kodem. 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 wiersz poleceń Firebase

Interfejs wiersza poleceń Firebase zapewnia narzędzia do zarządzania projektami Firebase. Interfejs wiersza poleceń jest wymagany do korzystania z Pakietu emulatorów, więc musisz go zainstalować.

Interfejs wiersza poleceń można zainstalować na różne sposoby. Jeśli używasz systemu macOS lub Linux, najprostszym sposobem jest uruchomienie tego polecenia z terminala:

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

Po zainstalowaniu interfejsu wiersza poleceń musisz uwierzytelnić się w Firebase.

  1. Zaloguj się do Firebase, korzystając ze swojego konta Google, uruchamiając następujące polecenie:
firebase login
  1. To polecenie łączy Twój komputer lokalny z Firebase i przyznaje Ci dostęp do projektów Firebase.
  1. Sprawdź, czy interfejs wiersza poleceń jest prawidłowo zainstalowany i ma dostęp do Twojego konta, wyświetlając listę projektów Firebase. Uruchom to polecenie:
firebase projects:list
  1. Wyświetlona lista powinna być taka sama jak projekty Firebase wymienione w konsoli Firebase. Zobaczysz co najmniej firebase-flutter-codelab.

Instalowanie interfejsu wiersza poleceń FlutterFire

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

Najpierw zainstaluj interfejs wiersza poleceń:

dart pub global activate flutterfire_cli

Sprawdź, czy interfejs wiersza poleceń został zainstalowany. Uruchom podane niżej polecenie w katalogu projektu Flutter i upewnij się, że interfejs wiersza poleceń generuje menu pomocy.

flutterfire --help

Użyj interfejsu wiersza poleceń Firebase i interfejsu wiersza poleceń FlutterFire, aby dodać projekt Firebase do aplikacji Flutter

Po zainstalowaniu 2 interfejsów wiersza poleceń możesz konfigurować poszczególne usługi Firebase (na przykład Firestore), pobierać emulatory i dodawać Firebase do aplikacji Flutter za pomocą kilku poleceń w terminalu.

Najpierw dokończ konfigurację Firebase, uruchamiając to polecenie:

firebase init

To polecenie przeprowadzi Cię przez serię pytań niezbędnych do skonfigurowania projektu. Zrzuty ekranu pokazują przebieg tego procesu:

  1. Gdy pojawi się prośba o wybór funkcji, kliknij „Firestore” (Odpal). i „Emulatory”. (nie ma opcji uwierzytelniania, ponieważ nie używa ona konfiguracji, którą można modyfikować z poziomu plików projektów Flutter). fe6401d769be8f53.png
  2. Gdy pojawi się taka prośba, wybierz „Use an existing project” (Użyj istniejącego projektu).

f11dcab439e6ac1e.png

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

3bdc0c6934991c25.png

  1. Następnie zadamy Ci serię pytań na temat nadawania nazw plikom, które zostaną wygenerowane. Proponuję nacisnąć Enter przy każdym pytaniu, aby wybrać domyślną wartość. 9bfa2d507e199c59.png
  2. Na koniec trzeba skonfigurować emulatory. Wybierz z listy Firestore i uwierzytelnianie, a następnie naciśnij „Enter” na każde pytanie o konkretne porty, które mają być używane w poszczególnych emulatorach. Gdy pojawi się pytanie, czy chcesz używać interfejsu emulatora, wybierz domyślne ustawienie „Tak”.

Po zakończeniu tego procesu dane wyjściowe powinny wyglądać podobnie do tego na zrzucie ekranu poniżej.

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

8544e41037637b07.png

Konfigurowanie FlutterFire

Następnie możesz użyć FlutterFire, aby wygenerować kod Dart wymagany do korzystania z Firebase w aplikacji Flutter.

flutterfire configure

Po uruchomieniu tego polecenia pojawi się prośba o wybranie projektu Firebase, którego chcesz użyć, i platformy do skonfigurowania. W ramach tych ćwiczeń w programie przykłady pokazują wykorzystanie technologii Flutter Web, ale możesz skonfigurować projekt Firebase tak, aby używać wszystkich opcji.

Na poniższych zrzutach ekranu znajdziesz instrukcje, na które musisz odpowiedzieć.

619b7aca6dc15472.png 301c9534f594f472.png

Zrzut ekranu z danymi wyjściowymi po zakończeniu procesu. Jeśli znasz już Firebase, z pewnością zauważysz, że nie musisz tworzyć aplikacji w konsoli. Udało Ci się to zrobić za pomocą interfejsu wiersza poleceń FlutterFire.

12199a85ade30459.png

Dodawanie pakietów Firebase do aplikacji Flutter

Ostatnim krokiem konfiguracji jest dodanie odpowiednich pakietów Firebase do projektu Flutter. Sprawdź w terminalu, czy jesteś w katalogu głównym projektu Flutter (flutter-codelabs/firebase-emulator-suite/start). Następnie uruchom te 3 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

Na razie konfiguracja aplikacji Flutter i Twojego projektu Firebase pozwala na używanie emulatorów, ale nadal musisz wskazać kodowi Flutter, aby przekierowywał wychodzące żądania Firebase na porty lokalne.

Najpierw dodaj kod inicjowania Firebase i kod konfiguracji emulatora do funkcji main w 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());
}

Kilka pierwszych wierszy kodu inicjuje Firebase. Prawie powszechnie, jeśli używasz Firebase w aplikacji Flutter, najlepiej zacząć od wywołania WidgetsFlutterBinding.ensureInitialized i Firebase.initializeApp.

Kod zaczynający się od wiersza if (kDebugMode) informuje aplikację, że ma być kierowana na emulatory, a nie na produkcyjny projekt Firebase. W kDebugMode kierowanie na emulatory działa tylko w środowisku programistycznym. kDebugMode jest wartością stałą, więc kompilator Dart wie, że w trybie publikacji musi całkowicie usunąć ten blok kodu.

Uruchom emulatory

Emulatory należy uruchomić przed uruchomieniem aplikacji Flutter. Najpierw uruchom emulatory, uruchamiając to w terminalu:

firebase emulators:start

To polecenie uruchamia emulatory i udostępnia porty lokalnego hosta, z którymi możemy wchodzić w interakcje. Po uruchomieniu tego polecenia dane wyjściowe powinny wyglądać podobnie do tego:

bb7181eb70829606.png

Dzięki temu dowiesz się, które emulatory są uruchomione oraz gdzie możesz je zobaczyć. Najpierw zapoznaj się z interfejsem emulatora na stronie localhost:4000.

11563f4c7216de81.png

To jest strona główna interfejsu lokalnego emulatora. Zawiera ona listę wszystkich dostępnych emulatorów. Każdy z nich ma stan włączony lub wyłączony.

5. Emulator uwierzytelniania Firebase

Pierwszym, którego użyjesz, będzie emulator uwierzytelniania. Aby zacząć korzystać z emulatora uwierzytelniania, kliknij „Otwórz emulator” na karcie Uwierzytelnianie w interfejsie zostanie wyświetlona strona podobna do tej:

3c1bfded40733189.png

Ta strona przypomina stronę konsoli internetowej uwierzytelniania. Zawiera ona tabelę z listą użytkowników takich jak konsola online oraz umożliwia ich ręczne dodawanie. Ważna różnica polega na tym, że jedyna metoda uwierzytelniania dostępna w emulatorach to adres e-mail i hasło. To wystarczy do lokalnego rozwoju.

Następnie przejdziesz przez proces dodawania użytkownika do emulatora uwierzytelniania Firebase i logowania go za pomocą interfejsu Flutter.

Dodawanie użytkownika

Kliknij „Dodaj użytkownika”. i wypełnij formularz tymi informacjami:

Po przesłaniu formularza tabela zawiera teraz użytkownika. Teraz możesz zaktualizować kod, aby zalogować się za pomocą tego użytkownika.

logged_out_view.dart,

Jedyny kod w widżecie LoggedOutView, który musi być zaktualizowany, to wywołanie zwrotne wywoływane, gdy użytkownik naciśnie przycisk logowania. Zaktualizuj kod tak:

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('[email protected]', 'dashword').then((_) {
                if (state.user != null) {
                 context.go('/');
                }
              });
              },
              child: const Text('Log In'),
          ),
        ),
      ],
    ),
   ),
  );
 }
}

Zaktualizowany kod zastępuje ciągi tekstowe TODO adresem e-mail i hasłem utworzonymi w emulatorze uwierzytelniania. W następnym wierszu wiersz if(true) został zastąpiony kodem, który sprawdza, czy state.user ma wartość null. Kod w języku AppClass rzuci więcej światła na tę kwestię.

app_state.dart

Trzeba zaktualizować 2 części kodu w języku: AppState. Najpierw nadaj członkowi klasy element AppState.user typ User z pakietu firebase_auth, a nie typu Object.

Następnie wypełnij metodę AppState.login zgodnie z poniższym przykładem:

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?. Te zajęcia w usłudze User pochodzą z Uwierzytelniania Firebase i dostarczają niezbędnych informacji, takich jak User.displayName, które omówię krótko.

To podstawowy kod potrzebny do zalogowania się użytkownika za pomocą adresu e-mail i hasła w Uwierzytelnianiu Firebase. wywołuje metodę FirebaseAuth w celu zalogowania, co zwraca obiekt Future<UserCredential>. Gdy przyszłość się zakończy, ten kod sprawdzi, czy UserCredential jest powiązany z elementem User. Jeżeli obiekt danych logowania zawiera użytkownika, oznacza to, że użytkownik się zalogował i można ustawić właściwość AppState.user. Jeśli go nie ma, oznacza to, że wystąpił błąd, który został wydrukowany.

Jedynym wierszem kodu w tej metodzie charakterystycznym dla tej aplikacji (a nie ogólnym kodem FirebaseAuth) jest wywołanie metody _listenForEntries, które omówimy w następnym kroku.

DO ZROBIENIA: ikona działania – odśwież aplikację i po jej wyrenderowaniu naciśnij przycisk logowania. Spowoduje to przejście do strony z komunikatem „Witamy z powrotem”. na górze ekranu. Uwierzytelnianie musi działać, ponieważ możesz przejść do tej strony, ale w celu wyświetlania nazwy użytkownika należy wprowadzić niewielką zmianę w usłudze logged_in_view.dart.

logged_in_view.dart

Zmień pierwszy wiersz 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 ten wiersz pobiera displayName z właściwości User obiektu AppState. Ten zasób (displayName) został ustawiony w emulatorze podczas zdefiniowania pierwszego użytkownika. W aplikacji powinien wyświetlić się komunikat „Witamy ponownie, Dash!”. podczas logowania, a nie TODO.

6. Odczyt i zapis danych w emulatorze Firestore

Najpierw sprawdź emulator Firestore. Na stronie głównej interfejsu emulatora (localhost:4000) kliknij „Otwórz emulator”. na karcie Firestore. Powinien on wyglądać podobnie do tego:

Emulator:

791fce7dc137910a.png

Konsola Firebase:

e0dde9aea34af050.png

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

  1. Możesz usunąć wszystkie dane jednym kliknięciem. Może to być niebezpieczne w przypadku danych produkcyjnych, ale jest pomocne w przypadku szybkich iteracji. Jeśli pracujesz nad nowym projektem i Twój model danych się zmienia, łatwo możesz go usunąć.
  2. Sekcja „Żądania” . Ta karta umożliwia śledzenie żądań przychodzących do tego emulatora. Omówię tę kartę bardziej szczegółowo.
  3. Nie ma żadnych kart Reguły, Indeksy i Wykorzystanie. Dostępne jest narzędzie (omówione w następnej sekcji), które pomaga w pisaniu reguł zabezpieczeń, ale nie możesz ustawiać reguł zabezpieczeń dla lokalnego emulatora.

Podsumowując, ta wersja Firestore zawiera więcej narzędzi przydatnych podczas programowania i usuwa narzędzia potrzebne w środowisku produkcyjnym.

Zapisz w Firestore

Przed omówieniem „Wniosków” w emulatorze, najpierw wyślij żądanie. Wymaga to aktualizacji kodu. Zacznij od podłączenia formularza w aplikacji do pisania nowego dziennika Entry w Firestore.

Ogólny proces przesyłania pliku Entry:

  1. Użytkownik wypełnia formularz i nacisnął przycisk Submit
  2. Interfejs wywołuje metodę AppState.writeEntryToFirebase
  3. AppState.writeEntryToFirebase dodaje wpis do Firebase

Nie trzeba zmieniać żadnego kodu używanego w krokach 1 ani 2. Jedyny kod, który będzie trzeba dodać w kroku 3, zostanie dodany do klasy AppState. Wprowadź tę zmianę w: 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,
   });
 }
 // ...
}

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

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

Po dodaniu tego kodu odśwież aplikację lub uruchom ją ponownie, zaloguj się i przejdź do widoku EntryForm. W formularzu możesz wpisać dowolną Strings. Pole Data może przyjmować dowolny ciąg znaków, ponieważ zostało to uproszczone na potrzeby tego ćwiczenia z programowania. Nie ma silnej weryfikacji ani w żaden sposób nie dba o obiekty DateTime).

Kliknij „Prześlij” na formularzu. W aplikacji nic się nie wydarzy, ale nowy wpis możesz zobaczyć w interfejsie emulatora.

Karta żądań w emulatorze Firestore

W interfejsie przejdź do emulatora Firestore i zajrzyj do sekcji „Dane”. . W katalogu głównym bazy danych powinna być już kolekcja o nazwie „Wpisy”. Powinien on zawierać dokument zawierający te same informacje, które zostały podane w formularzu.

A978fb34fb8a83da.png

Potwierdza to, że żądanie AppState.writeEntryToFirestore zostało zrealizowane. Teraz możesz dokładniej przeanalizować tę prośbę na karcie Prośby. Kliknij tę kartę.

Żądania emulatora Firestore

Powinna tam być lista podobna do tej:

f0b37f0341639035.png

Klikając dowolny element listy, możesz wyświetlić sporo przydatnych informacji. Kliknij pozycję na liście CREATE odpowiadającą Twojej prośbie o utworzenie nowego wpisu w dzienniku. Pojawi się nowa tabela podobna do tej:

385d62152e99aad4.png

Jak już wspomnieliśmy, emulator Firestore zapewnia narzędzia do tworzenia reguł zabezpieczeń aplikacji. Ten widok pokazuje dokładnie, w którym wierszu reguł zabezpieczeń dane żądanie zostało przekazane (lub zostało odrzucone, jeśli tak się stało). W przypadku bardziej niezawodnej aplikacji reguły zabezpieczeń mogą się rozwijać i podlegać wielu testom autoryzacji. Ten widok jest używany do pisania i debugowania tych reguł autoryzacji.

Zapewnia to też prosty sposób na sprawdzenie każdego fragmentu tego żądania, łącznie z metadanymi i danymi uwierzytelniania. Te dane służą do pisania złożonych reguł autoryzacji.

Odczytuję z Firestore

Firestore stosuje synchronizację do przekazywania zaktualizowanych danych na połączone urządzenia. W kodzie Flutter możesz nasłuchiwać (lub zasubskrybować) kolekcje i dokumenty 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 AppState._listenForEntries.

Kod ten działa w połączeniu z kodami StreamController i Stream o nazwach odpowiednio AppState._entriesStreamController i AppState.entries. Ten kod został już zapisany oraz cały kod potrzebny w interfejsie użytkownika do wyświetlania danych z Firestore.

Zaktualizuj metodę _listenForEntries tak, aby pasowała do poniższego kodu:

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

Ten kod nasłuchuje „wpisów” w Firestore. Gdy Firestore powiadamia tego klienta o nowych danych, przekazuje je, a kod w _listenForEntries zmienia wszystkie jego dokumenty podrzędne w obiekt, którego aplikacja może używać (Entry). Następnie dodaje te wpisy do tabeli StreamController o nazwie _entriesStreamController (odtwarza ją interfejs użytkownika). To jedyna wymagana aktualizacja tego kodu.

Pamiętaj, że metoda AppState.logIn wywołuje metodę _listenForEntries, która rozpoczyna proces nasłuchiwania, gdy użytkownik się zaloguje.

// ...
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ę. Powinien wyglądać tak:

b8a31c7a8900331.gif

7. Eksportowanie i importowanie danych do emulatora

Emulatory Firebase obsługują importowanie i eksportowanie danych. Import i eksporty pozwalają kontynuować programowanie z użyciem tych samych danych, gdy zrobisz sobie przerwę w pracy, a potem ją wznowisz. Możesz też przekazywać pliki danych do Gita. Inni deweloperzy, z którymi pracujesz, będą mieli dostęp do tych samych danych.

Eksportuj dane emulatora

Najpierw wyeksportuj dane emulatora, które już masz. Gdy emulatory są jeszcze uruchomione, otwórz nowe okno terminala i wpisz to polecenie:

firebase emulators:export ./emulators_data

.emulators_data to argument informujący Firebase, gdzie wyeksportować dane. Jeśli katalog nie istnieje, zostanie utworzony. Nazwa katalogu może być dowolna.

Po uruchomieniu polecenia w terminalu, w którym zostało uruchomione, wyświetlą się dane wyjściowe:

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

Jeśli przełączysz się na okno terminala, w którym działają emulatory, zobaczysz te 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 projektu, zobaczysz 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 zacząć od miejsca, w którym został przerwany.

Najpierw zatrzymaj emulatory, jeśli są uruchomione, naciskając CTRL+C w terminalu.

Następnie uruchom dotychczasowe polecenie emulators:start z flagą wskazującą, jakie dane należy zaimportować:

firebase emulators:start --import ./emulators_data

Gdy emulatory będą działać, przejdź do interfejsu emulatora na stronie localhost:4000. Zobaczysz wtedy te same dane co wcześniej.

Automatycznie eksportuj dane po zamknięciu emulatorów

Możesz też eksportować dane automatycznie po zamknięciu emulatorów, bez konieczności eksportowania danych pod koniec każdej sesji programowania.

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

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

Gotowe. Twoje dane będą teraz zapisywane i odświeżane za każdym razem, gdy będziesz używać emulatorów w tym projekcie. Możesz też podać inny katalog jako argument funkcji –export-on-exit flag, ale domyślnie będzie to katalog przekazywany do –import.

Możesz także używać dowolnej kombinacji tych opcji. To notatka z dokumentów: katalog eksportu można określić za pomocą tej flagi: firebase emulators:start --export-on-exit=./saved-data. Jeśli używasz --import, domyślna ścieżka eksportu jest taka sama; na przykład: firebase emulators:start --import=./data-path --export-on-exit. Na koniec, jeśli to konieczne, przekaż różne ścieżki katalogów do flag --import i --export-on-exit.

8. Gratulacje!

Udało Ci się ukończyć pierwsze kroki w emulatorze Firebase i oprogramowaniu Flutter. Ukończony kod ćwiczenia z programowania znajdziesz w sekcji „complete” katalog w github: Flutter Codelabs

Omówione zagadnienia

  • Konfigurowanie aplikacji Flutter na potrzeby Firebase
  • Konfiguruję projekt Firebase
  • Interfejs wiersza poleceń FlutterFire
  • wiersz poleceń Firebase
  • Emulator uwierzytelniania Firebase
  • Emulator Firebase Firestore
  • Importowanie i eksportowanie danych emulatora

Następne kroki

Więcej informacji

Sparky jest z Ciebie dumny!

2a0ad195769368b1.gif