Локальная разработка ваших приложений Flutter с использованием Firebase Emulator Suite.

1. Прежде чем начать

В этой лаборатории вы узнаете, как использовать Firebase Emulator Suite с Flutter во время локальной разработки. Вы узнаете, как использовать аутентификацию по паролю электронной почты через Emulator Suite, а также как читать и записывать данные в эмулятор Firestore. Наконец, вы поработаете с импортом и экспортом данных из эмуляторов, чтобы работать с одними и теми же поддельными данными каждый раз, когда вы возвращаетесь к разработке.

Предварительные условия

В этой кодовой лаборатории предполагается, что у вас есть некоторый опыт работы с Flutter. Если нет, возможно, вы захотите сначала изучить основы. Следующие ссылки полезны:

У вас также должен быть некоторый опыт работы с Firebase, но ничего страшного, если вы никогда не добавляли Firebase в проект Flutter. Если вы не знакомы с консолью Firebase или вообще не знакомы с Firebase, сначала просмотрите следующие ссылки:

Что вы создадите

Эта лаборатория кода поможет вам создать простое приложение для ведения журнала. Приложение будет иметь экран входа в систему и экран, который позволит вам читать предыдущие записи журнала и создавать новые.

cd5c4753bbee8af.png8cb4d21f656540bf.png

Что вы узнаете

Вы узнаете, как начать использовать Firebase, а также как интегрировать и использовать пакет эмулятора Firebase в рабочий процесс разработки Flutter. Будут рассмотрены следующие темы Firebase:

Обратите внимание, что эти темы рассматриваются в той мере, в какой они необходимы для описания пакета эмулятора Firebase. Эта лаборатория кода ориентирована на добавление проекта Firebase в ваше приложение Flutter и разработку с использованием пакета эмулятора Firebase. Подробных обсуждений по аутентификации Firebase или Firestore не будет. Если вы незнакомы с этими темами, мы рекомендуем начать с лаборатории «Знакомство с Firebase для Flutter» .

Что вам понадобится

  • Знание Flutter и установленного SDK.
  • Текстовые редакторы Intellij JetBrains или VS Code
  • Браузер Google Chrome (или другая предпочитаемая вами цель разработки для Flutter. Некоторые команды терминала в этой лаборатории предполагают, что вы запускаете свое приложение в Chrome)

2. Создайте и настройте проект Firebase.

Первая задача, которую вам необходимо выполнить, — это создать проект Firebase в веб-консоли Firebase. Подавляющее большинство этой лаборатории будет посвящено Emulator Suite, который использует локально работающий пользовательский интерфейс, но сначала вам необходимо настроить полный проект Firebase.

Создать проект Firebase

  1. Войдите в консоль Firebase.
  2. В консоли Firebase нажмите «Добавить проект» (или «Создать проект» ) и введите имя вашего проекта Firebase (например, « Firebase-Flutter-Codelab») .

fe6aeab3b91965ed.png

  1. Просмотрите параметры создания проекта. Примите условия Firebase, если будет предложено. Пропустите настройку Google Analytics, поскольку вы не будете использовать Analytics для этого приложения.

d1fcec48bf251eaa.png

Дополнительные сведения о проектах Firebase см. в разделе Общие сведения о проектах Firebase .

Приложение, которое вы создаете, использует два продукта Firebase, доступные для приложений Flutter:

  • Аутентификация Firebase , позволяющая пользователям входить в ваше приложение.
  • Cloud Firestore для сохранения структурированных данных в облаке и получения мгновенных уведомлений при изменении данных.

Эти два продукта требуют специальной настройки или их необходимо включить с помощью консоли Firebase.

Включить Cloud Firestore

Приложение Flutter использует Cloud Firestore для сохранения записей журнала.

Включить Cloud Firestore:

  1. В разделе «Сборка» консоли Firebase нажмите Cloud Firestore .
  2. Нажмите Создать базу данных . 99e8429832d23fa3.png
  3. Выберите опцию «Запустить в тестовом режиме» . Прочтите отказ от ответственности о правилах безопасности. Тестовый режим гарантирует, что вы можете свободно писать в базу данных во время разработки. Нажмите "Далее . 6be00e26c72ea032.png
  4. Выберите местоположение для вашей базы данных (вы можете просто использовать значение по умолчанию). Обратите внимание, что это местоположение невозможно изменить позже. 278656eefcfb0216.png
  5. Нажмите Включить .

3. Настройте приложение Flutter.

Прежде чем мы начнем, вам нужно будет скачать стартовый код и установить интерфейс командной строки Firebase.

Получить стартовый код

Клонируйте репозиторий GitHub из командной строки:

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

В качестве альтернативы, если у вас установлен инструмент командной строки GitHub :

gh repo clone flutter/codelabs flutter-codelabs

Пример кода следует клонировать в каталог flutter-codelabs , который содержит код для коллекции codelabs. Код этой лаборатории кода находится в flutter-codelabs/firebase-emulator-suite .

Структура каталогов flutter-codelabs/firebase-emulator-suite представляет собой два проекта Flutter. Один из них называется complete , и вы можете обратиться к нему, если хотите пропустить этап или сделать перекрестную ссылку на свой собственный код. Другой проект называется start .

Код, с которого вы хотите начать, находится в каталоге flutter-codelabs/firebase-emulator-suite/start . Откройте или импортируйте этот каталог в предпочитаемую вами среду IDE.

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

Установите интерфейс командной строки Firebase

Интерфейс командной строки Firebase предоставляет инструменты для управления вашими проектами Firebase. Для использования Emulator Suite необходим интерфейс командной строки, поэтому вам необходимо его установить.

Существует множество способов установки CLI. Самый простой способ, если вы используете MacOS или Linux, — запустить эту команду со своего терминала:

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

После установки CLI вы должны пройти аутентификацию в Firebase.

  1. Войдите в Firebase, используя свою учетную запись Google, выполнив следующую команду:
firebase login
  1. Эта команда подключает ваш локальный компьютер к Firebase и предоставляет вам доступ к вашим проектам Firebase.
  1. Проверьте, правильно ли установлен интерфейс командной строки и имеет ли он доступ к вашей учетной записи, перечислив свои проекты Firebase. Выполните следующую команду:
firebase projects:list
  1. Отображаемый список должен быть таким же, как проекты Firebase, перечисленные в консоли Firebase . Вы должны увидеть как минимум firebase-flutter-codelab.

Установите интерфейс командной строки FlutterFire.

Интерфейс командной строки FlutterFire построен на основе интерфейса командной строки Firebase и упрощает интеграцию проекта Firebase с вашим приложением Flutter.

Сначала установите CLI:

dart pub global activate flutterfire_cli

Убедитесь, что CLI установлен. Запустите следующую команду в каталоге проекта Flutter и убедитесь, что CLI выводит меню справки.

flutterfire --help

Используйте Firebase CLI и FlutterFire CLI, чтобы добавить проект Firebase в приложение Flutter.

Установив два интерфейса командной строки, вы можете настроить отдельные продукты Firebase (например, Firestore), загрузить эмуляторы и добавить Firebase в свое приложение Flutter с помощью всего лишь пары команд терминала.

Сначала завершите настройку Firebase, выполнив следующую команду:

firebase init

Эта команда проведет вас через ряд вопросов, необходимых для настройки вашего проекта. На этих скриншотах показан процесс:

  1. Когда будет предложено выбрать функции, выберите «Firestore» и «Эмуляторы». (Опция аутентификации отсутствует, поскольку она не использует конфигурацию, которую можно изменить из файлов проекта Flutter.) fe6401d769be8f53.png
  2. Затем при появлении запроса выберите «Использовать существующий проект».

f11dcab439e6ac1e.png

  1. Теперь выберите проект, созданный на предыдущем шаге: flutter-firebase-codelab.

3bdc0c6934991c25.png

  1. Далее вам будет задан ряд вопросов об именах создаваемых файлов. Я предлагаю нажимать «ввод» для каждого вопроса, чтобы выбрать вариант по умолчанию. 9bfa2d507e199c59.png
  2. Наконец, вам нужно настроить эмуляторы. Выберите Firestore и аутентификацию из списка, а затем нажмите «Ввод» на каждый вопрос о конкретных портах, которые будут использоваться для каждого эмулятора. Вам следует выбрать значение по умолчанию «Да», когда вас спросят, хотите ли вы использовать пользовательский интерфейс эмулятора.

В конце процесса вы должны увидеть результат, похожий на следующий снимок экрана.

Важно : ваш результат может немного отличаться от моего, как показано на скриншоте ниже, поскольку последний вопрос по умолчанию будет «Нет», если у вас уже загружены эмуляторы.

8544e41037637b07.png

Настроить FlutterFire

Затем вы можете использовать FlutterFire для создания необходимого кода Dart для использования Firebase в вашем приложении Flutter.

flutterfire configure

При запуске этой команды вам будет предложено выбрать, какой проект Firebase вы хотите использовать и какие платформы вы хотите настроить. В этой лаборатории кода в примерах используется Flutter Web, но вы можете настроить свой проект Firebase на использование всех параметров.

На следующих снимках экрана показаны запросы, на которые вам нужно будет ответить.

619b7aca6dc15472.png301c9534f594f472.png

На этом снимке экрана показан результат завершения процесса. Если вы знакомы с Firebase, вы заметите, что вам не нужно создавать приложения в консоли, и интерфейс командной строки FlutterFire сделал это за вас.

12199a85ade30459.png

Добавьте пакеты Firebase в приложение Flutter

Последний шаг настройки — добавить соответствующие пакеты Firebase в ваш проект Flutter. В терминале убедитесь, что вы находитесь в корне проекта Flutter по адресу flutter-codelabs/firebase-emulator-suite/start . Затем выполните три следующие команды:

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

Это единственные пакеты, которые вы будете использовать в этом приложении.

4. Включение эмуляторов Firebase

На данный момент приложение Flutter и ваш проект Firebase настроены на использование эмуляторов, но вам все равно нужно указать коду Flutter перенаправлять исходящие запросы Firebase на локальные порты.

Сначала добавьте код инициализации Firebase и код настройки эмулятора к main функции в 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());
}

Первые несколько строк кода инициализируют Firebase. Почти всегда, если вы работаете с Firebase в приложении Flutter, вам нужно начать с вызова WidgetsFlutterBinding.ensureInitialized и Firebase.initializeApp .

После этого код, начинающийся со строки if (kDebugMode) указывает вашему приложению ориентироваться на эмуляторы, а не на производственный проект Firebase. kDebugMode гарантирует, что нацеливание на эмуляторы произойдет только в том случае, если вы находитесь в среде разработки. Поскольку kDebugMode является постоянным значением, компилятор Dart знает, что этот блок кода необходимо полностью удалить в режиме выпуска.

Запустите эмуляторы

Вам следует запустить эмуляторы перед запуском приложения Flutter. Сначала запустите эмуляторы, запустив это в терминале:

firebase emulators:start

Эта команда загружает эмуляторы и предоставляет порты локального хоста, с которыми мы можем взаимодействовать с ними. Когда вы запустите эту команду, вы должны увидеть вывод, подобный этому:

bb7181eb70829606.png

Эти выходные данные сообщают вам, какие эмуляторы запущены и где вы можете их просмотреть. Сначала проверьте пользовательский интерфейс эмулятора по адресу localhost:4000 .

11563f4c7216de81.png

Это домашняя страница пользовательского интерфейса локального эмулятора. В нем перечислены все доступные эмуляторы, и каждый из них помечен статусом «включено» или «выключено».

5. Эмулятор Firebase Auth.

Первый эмулятор, который вы будете использовать, — это эмулятор аутентификации. Начните с эмулятора аутентификации, нажав «Перейти к эмулятору» на карточке аутентификации в пользовательском интерфейсе, и вы увидите страницу, которая выглядит следующим образом:

3c1bfded40733189.png

Эта страница похожа на страницу веб-консоли Auth. Он имеет таблицу со списком пользователей, как и онлайн-консоль, и позволяет добавлять пользователей вручную. Одно большое отличие здесь заключается в том, что единственный вариант метода аутентификации, доступный в эмуляторах, — это адрес электронной почты и пароль. Этого достаточно для местного развития.

Далее вы пройдете процесс добавления пользователя в эмулятор Firebase Auth, а затем авторизуете этого пользователя через пользовательский интерфейс Flutter.

Добавить пользователя

Нажмите кнопку «Добавить пользователя» и заполните форму, указав следующую информацию:

  • Отображаемое имя: Дэш
  • Электронная почта: Dash@email.com
  • Пароль: тиреворд

Отправьте форму, и вы увидите, что в таблице теперь есть пользователь. Теперь вы можете обновить код для входа в систему под этим пользователем.

logged_out_view.dart

Единственный код в виджете LoggedOutView , который необходимо обновить, — это обратный вызов, который запускается, когда пользователь нажимает кнопку входа в систему. Обновите код, чтобы он выглядел следующим образом:

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

Обновленный код заменяет строки TODO на адрес электронной почты и пароль, которые вы создали в эмуляторе аутентификации. А в следующей строке строка if(true) заменена кодом, который проверяет, имеет ли значение state.user значение null. Код в AppClass проливает на это больше света.

app_state.dart

Необходимо обновить две части кода в AppState . Во-первых, присвойте члену класса AppState.user тип User из пакета firebase_auth , а не тип Object .

Во-вторых, заполните метод AppState.login , как показано ниже:

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

Определение типа пользователя теперь User? . Этот класс User взят из Firebase Auth и предоставляет необходимую информацию, такую ​​как User.displayName , которая обсуждается немного позже.

Это базовый код, необходимый для входа пользователя с помощью адреса электронной почты и пароля в Firebase Auth. Он вызывает FirebaseAuth для входа, который возвращает объект Future<UserCredential> . Когда будущее завершается, этот код проверяет, есть ли User прикрепленный к UserCredential . Если в объекте учетных данных есть пользователь, значит, пользователь успешно вошел в систему, и можно установить свойство AppState.user . Если нет, то произошла ошибка, и она напечатана.

Обратите внимание, что единственная строка кода в этом методе, специфичная для этого приложения (а не общий код FirebaseAuth), — это вызов метода _listenForEntries , который будет рассмотрен на следующем шаге.

TODO: Значок действия: перезагрузите приложение, а затем нажмите кнопку «Войти», когда оно отобразится. Это приведет к тому, что приложение перейдет на страницу с надписью «С возвращением, человек!» на вершине. Аутентификация должна работать, поскольку она позволяет вам перейти на эту страницу, но необходимо внести небольшое обновление в logged_in_view.dart , чтобы отобразить фактическое имя пользователя.

logged_in_view.dart

Измените первую строку в методе 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(
 // ...

Теперь эта строка получает displayName из свойства User объекта AppState . Это displayName было установлено в эмуляторе, когда вы определили своего первого пользователя. Теперь ваше приложение должно отображать «С возвращением, Дэш!» при входе в систему, а не TODO .

6. Чтение и запись данных в эмулятор Firestore.

Сначала проверьте эмулятор Firestore. На домашней странице пользовательского интерфейса эмулятора ( localhost:4000 ) нажмите «Перейти к эмулятору» на карточке Firestore. Это должно выглядеть так:

Эмулятор:

791fce7dc137910a.png

Консоль Firebase:

e0dde9aea34af050.png

Если у вас есть опыт работы с Firestore, вы заметите, что эта страница похожа на страницу Firestore консоли Firebase. Однако есть несколько заметных отличий.

  1. Вы можете удалить все данные нажатием одной кнопки. Это было бы опасно для производственных данных, но полезно для быстрой итерации! Если вы работаете над новым проектом и ваша модель данных изменилась, это легко исправить.
  2. Есть вкладка «Заявки». Эта вкладка позволяет вам просматривать входящие запросы к этому эмулятору. Я расскажу об этой вкладке более подробно чуть позже.
  3. Вкладки «Правила», «Индексы» и «Использование» отсутствуют. Существует инструмент (обсуждаемый в следующем разделе), который помогает писать правила безопасности, но вы не можете установить правила безопасности для локального эмулятора.

Подводя итог этому списку, можно сказать, что эта версия Firestore предоставляет больше инструментов, полезных во время разработки, и удаляет инструменты, необходимые в рабочей среде.

Напишите в Firestore

Прежде чем обсуждать вкладку «Запросы» в эмуляторе, сначала сделайте запрос. Это требует обновлений кода. Начните с подключения формы в приложении для записи новой Entry журнала в Firestore.

Высокоуровневый процесс подачи Entry :

  1. Пользователь заполняет форму и нажимает кнопку Submit .
  2. Пользовательский интерфейс вызывает AppState.writeEntryToFirebase .
  3. AppState.writeEntryToFirebase добавляет запись в Firebase

Никакой код, задействованный на шаге 1 или 2, менять не нужно. Единственный код, который необходимо добавить для шага 3, будет добавлен в класс AppState . Внесите следующее изменение в 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,
   });
 }
 // ...
}

Код метода writeEntryToFirebase получает ссылку на коллекцию под названием «Entries» в Firestore. Затем он добавляет новую запись, которая должна иметь тип Map<String, String> .

В данном случае коллекции «Записи» в Firestore не существовало, поэтому Firestore создал ее.

После добавления этого кода выполните «горячую» перезагрузку или перезапуск приложения, войдите в систему и перейдите к представлению EntryForm . Вы можете заполнить форму любыми Strings которые вам нужны. (Поле Date будет принимать любую строку, так как оно было упрощено для этой кодовой лаборатории. Оно не имеет строгой проверки или каким-либо образом заботится об объектах DateTime .)

Нажмите «Отправить» в форме. В приложении ничего не произойдет, но вы сможете увидеть новую запись в пользовательском интерфейсе эмулятора.

Вкладка запросов в эмуляторе Firestore

В пользовательском интерфейсе перейдите к эмулятору Firestore и просмотрите вкладку «Данные». Вы должны увидеть, что в корне вашей базы данных теперь есть коллекция под названием «Записи». Там должен быть документ, содержащий ту же информацию, которую вы ввели в форму.

a978fb34fb8a83da.png

Это подтверждает, что AppState.writeEntryToFirestore сработал, и теперь вы можете продолжить изучение запроса на вкладке «Запросы». Нажмите на эту вкладку сейчас.

Запросы эмулятора Firestore

Здесь вы должны увидеть список, похожий на этот:

f0b37f0341639035.png

Вы можете щелкнуть любой из этих элементов списка и увидеть немало полезной информации. Нажмите на элемент списка CREATE , соответствующий вашему запросу на создание новой записи журнала. Вы увидите новую таблицу, которая выглядит следующим образом:

385d62152e99aad4.png

Как уже упоминалось, эмулятор Firestore предоставляет инструменты для разработки правил безопасности вашего приложения. В этом представлении показано, какую именно строку в ваших правилах безопасности этот запрос прошел (или не прошел, если это так). В более надежном приложении правила безопасности могут расширяться и иметь несколько проверок авторизации. Это представление используется для помощи в написании и отладке правил авторизации.

Он также обеспечивает простой способ проверки каждой части этого запроса, включая метаданные и данные аутентификации. Эти данные используются для написания сложных правил авторизации.

Чтение из Firestore

Firestore использует синхронизацию данных для передачи обновленных данных на подключенные устройства. В коде Flutter вы можете слушать (или подписываться) на коллекции и документы Firestore, и ваш код будет уведомляться о каждом изменении данных. В этом приложении прослушивание обновлений Firestore осуществляется с помощью метода AppState._listenForEntries .

Этот код работает совместно с StreamController и Stream , называемыми AppState._entriesStreamController и AppState.entries соответственно. Этот код уже написан, как и весь код, необходимый в пользовательском интерфейсе для отображения данных из Firestore.

Обновите метод _listenForEntries , чтобы он соответствовал приведенному ниже коду:

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

Этот код прослушивает коллекцию «Entries» в Firestore. Когда Firestore уведомляет этот клиент о наличии новых данных, он передает эти данные, и код в _listenForEntries превращает все его дочерние документы в объект, который может использовать наше приложение ( Entry ). Затем он добавляет эти записи в StreamController с именем _entriesStreamController (который прослушивает пользовательский интерфейс). Этот код является единственным необходимым обновлением.

Наконец, вспомните, что метод AppState.logIn вызывает _listenForEntries , который начинает процесс прослушивания после входа пользователя в систему.

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

Теперь запустите приложение. Это должно выглядеть так:

b8a31c7a8900331.gif

7. Экспорт и импорт данных в эмулятор.

Эмуляторы Firebase поддерживают импорт и экспорт данных. Использование импорта и экспорта позволяет вам продолжить разработку с теми же данными, когда вы сделаете перерыв в разработке, а затем возобновите ее. Вы также можете зафиксировать файлы данных в git, и другие разработчики, с которыми вы работаете, будут иметь те же данные для работы.

Экспорт данных эмулятора

Сначала экспортируйте уже имеющиеся у вас данные эмулятора. Пока эмуляторы все еще работают, откройте новое окно терминала и введите следующую команду:

firebase emulators:export ./emulators_data

.emulators_data — это аргумент, который сообщает Firebase, куда экспортировать данные. Если каталог не существует, он создается. Вы можете использовать любое имя для этого каталога.

Когда вы запустите эту команду, вы увидите этот вывод в терминале, где вы выполнили команду:

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

И если вы переключитесь на окно терминала, где работают эмуляторы, вы увидите следующий вывод:

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

И, наконец, если вы заглянете в каталог своего проекта, вы увидите каталог с именем ./emulators_data , который содержит файлы JSON , среди других файлов метаданных, с сохраненными вами данными.

Импортировать данные эмулятора

Теперь вы можете импортировать эти данные в рамках рабочего процесса разработки и начать с того места, на котором остановились.

Сначала остановите эмуляторы, если они запущены, нажав CTRL+C в терминале.

Затем запустите команду emulators:start , которую вы уже видели, но с флагом, указывающим, какие данные импортировать:

firebase emulators:start --import ./emulators_data

Когда эмуляторы заработают, перейдите к пользовательскому интерфейсу эмулятора по адресу localhost:4000 , и вы должны увидеть те же данные, с которыми работали ранее.

Автоматический экспорт данных при закрытии эмуляторов

Вы также можете экспортировать данные автоматически при выходе из эмуляторов, не забывая экспортировать данные в конце каждого сеанса разработки.

При запуске эмуляторов запустите команду emulators:start с двумя дополнительными флагами.

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

Вуаля! Ваши данные теперь будут сохраняться и перезагружаться каждый раз, когда вы работаете с эмуляторами этого проекта. Вы также можете указать другой каталог в качестве аргумента –export-on-exit flag , но по умолчанию будет использоваться каталог, переданный в –import .

Вы также можете использовать любую комбинацию этих опций. Это примечание из документации : каталог экспорта можно указать с помощью этого флага: firebase emulators:start --export-on-exit=./saved-data . Если используется --import , путь экспорта по умолчанию тот же; например: firebase emulators:start --import=./data-path --export-on-exit . Наконец, если хотите, передайте разные пути к каталогам флагам --import и --export-on-exit .

8. Поздравляем!

Вы завершили подготовку к работе с эмулятором Firebase и Flutter. Вы можете найти готовый код для этой Codelab в «полном» каталоге на github: Flutter Codelabs.

Что мы рассмотрели

  • Настройка приложения Flutter для использования Firebase
  • Настройка проекта Firebase
  • Интерфейс командной строки FlutterFire
  • Интерфейс командной строки Firebase
  • Эмулятор аутентификации Firebase
  • Эмулятор Firebase Firestore
  • Импорт и экспорт данных эмулятора

Следующие шаги

Узнать больше

Спарки гордится тобой!

2a0ad195769368b1.gif