Познакомьтесь с Firebase для Flutter

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

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

Предпосылки

Это codelab предполагает , что вы знакомы с флаттером, и вы установили флаттер SDK и редактор .

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

В этой кодовой лаборатории вы создадите приложение для RSVP событий и чата гостевой книги на Android, iOS, в Интернете и macOS с помощью Flutter. Вы будете аутентифицировать пользователей с помощью Firebase Authentication и синхронизировать данные с помощью Cloud Firestore.

Что тебе понадобится

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

  • Физическое устройство (Android или iOS), подключенное к вашему компьютеру и переведенное в режим разработчика.
  • Симулятор iOS. (Требует установки инструментов Xcode .)
  • Эмулятор Android. (Требует установки в Android Studio .)

Помимо вышеперечисленного, вам также понадобятся:

  • Любой браузер, например Chrome.
  • IDE или текстовый редактор вашего выбора, такие как Android Studio или VS кодекс сконфигурированных с плагиными Dart и флаттера.
  • Последняя stable версия флаттера (или beta , если вам нравится жить на краю).
  • Учетная запись Google, например учетная запись Gmail, для создания проекта Firebase и управления им.
  • Пример кода codelab. См. Следующий шаг, чтобы узнать, как получить код.

2. Получите образец кода.

Начнем с загрузки начальной версии нашего проекта с GitHub.

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

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

С другой стороны , если у вас есть Cli GitHub в инструмент установлен:

gh repo clone flutter/codelabs flutter-codelabs

Пример кода должен быть клонирован в flutter-codelabs каталог, который содержит код для сбора codelabs. Код для этого codelab в flutter-codelabs/firebase-get-to-know-flutter .

Структура каталогов под flutter-codelabs/firebase-get-to-know-flutter представляет собой серию снимков , где вы должны быть в конце каждого указанного шага. Это шаг 2, поэтому найти подходящие файлы очень просто:

cd flutter-codelabs/firebase-get-to-know-flutter/step_02

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

Импортируйте стартовое приложение

Открыть или импортировать flutter-codelabs/firebase-get-to-know-flutter/step_02 каталогу в предпочитаемый IDE. Этот каталог содержит начальный код для codelab, который состоит из еще не работающего приложения для встреч Flutter.

Найдите файлы для работы

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

Найдите в проекте следующие файлы:

  • lib/main.dart : Этот файл содержит главную точку входа и виджет приложения.
  • lib/src/widgets.dart : Этот файл содержит несколько виджетов , чтобы помочь стандартизировать стайлинг приложения. Они используются для создания экрана стартового приложения.
  • lib/src/authentication.dart : Этот файл содержит частичную реализацию FirebaseUI Auth с набором виджетов , чтобы создать пользовательский интерфейс входа в систему для проверки подлинности на основе Firebase электронной почты. Эти виджеты для потока аутентификации еще не используются в начальном приложении, но вы скоро подключите их.

Вы добавите дополнительные файлы по мере необходимости для построения остальной части приложения.

Рассматривая lib/main.dart файл

Это приложение использует в google_fonts пакет , чтобы позволить нам сделать Roboto шрифт по умолчанию на протяжении всего приложения. Упражнение для мотивированного читателя исследовать fonts.google.com и использовать шрифты , вы обнаружите там в разных частях приложения.

Вы используя вспомогательные виджеты lib/src/widgets.dart в виде Header , Paragraph и IconAndDetail . Эти виджеты загромождать в макете страницы , описанном в HomePage , исключив дублирование кода. Это дает дополнительное преимущество, обеспечивая единообразный внешний вид.

Вот как ваше приложение выглядит на Android, iOS, в Интернете и macOS:

Предварительный просмотр приложения

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

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

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

  1. Войдите Firebase .
  2. В консоли Firebase, нажмите кнопку Add Project (или Создать проект), и название вашего проекта Firebase Firebase-флаттер-Codelab.

4395e4e67c08043a.png

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

b7138cde5f2c7b61.png

Чтобы узнать больше о проектах Firebase см Понимать проекты Firebase .

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

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

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

Включить знак электронной почты в течение Firebase аутентификации

Для того, чтобы позволить пользователям войти в веб - приложение, вы будете использовать E - mail / пароль входа в методе для этого codelab:

  1. В Firebase консоли разверните меню сборки на левой панели.
  2. Нажмите Authentication, а затем нажмите кнопку Начало, а затем вкладку регистрации в методе (или нажмите здесь , чтобы перейти непосредственно к Знамению-во вкладке метода).
  3. Нажмите E - mail / пароль в регистрации в списке поставщиков, установите переключатель Включить в положение, а затем нажмите кнопку Сохранить. 58e3e3e23c2f16a4.png

Включить Cloud Firestore

Веб - приложение использует облако Firestore для сохранения сообщений чата и получать новые сообщения чата.

Включить Cloud Firestore:

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

4. Конфигурация Firebase.

Чтобы использовать Firebase с Flutter, вам необходимо выполнить процесс настройки проекта Flutter для правильного использования библиотек FlutterFire:

  • Добавьте зависимости FlutterFire в свой проект
  • Зарегистрируйте желаемую платформу в проекте Firebase
  • Загрузите файл конфигурации для конкретной платформы и добавьте его в код.

В каталоге верхнего уровня вашего приложения Flutter, есть подкаталоги называемых ios и android . Эти каталоги содержат файлы конфигурации для конкретной платформы для iOS и Android соответственно.

Настроить зависимости

Вам необходимо добавить библиотеки FlutterFire для двух продуктов Firebase, которые вы используете в этом приложении - Firebase Auth и Cloud Firestore. Выполните следующие три команды, чтобы добавить зависимости.

$ flutter pub add firebase_core
Resolving dependencies...
  async 2.8.1 (2.8.2 available)
+ firebase_core 1.6.0
+ firebase_core_platform_interface 4.0.1
+ firebase_core_web 1.1.0
+ flutter_web_plugins 0.0.0 from sdk flutter
+ js 0.6.3
  matcher 0.12.10 (0.12.11 available)
  path_provider 2.0.2 (2.0.3 available)
  platform 3.0.0 (3.0.2 available)
  test_api 0.4.2 (0.4.3 available)
  win32 2.2.5 (2.2.9 available)
Changed 5 dependencies!

firebase_core является общий код требуется для всех плагинов Firebase флаттера.

$ flutter pub add firebase_auth
Resolving dependencies...
  async 2.8.1 (2.8.2 available)
+ firebase_auth 3.1.0
+ firebase_auth_platform_interface 6.1.0
+ firebase_auth_web 3.1.0
+ intl 0.17.0
  matcher 0.12.10 (0.12.11 available)
  path_provider 2.0.2 (2.0.3 available)
  platform 3.0.0 (3.0.2 available)
  test_api 0.4.2 (0.4.3 available)
  win32 2.2.5 (2.2.9 available)
Changed 4 dependencies!

firebase_auth обеспечивает интеграцию с возможностью аутентификации Firebase в.

$ flutter pub add cloud_firestore
Resolving dependencies...
  async 2.8.1 (2.8.2 available)
+ cloud_firestore 2.5.1
+ cloud_firestore_platform_interface 5.4.1
+ cloud_firestore_web 2.4.1
  matcher 0.12.10 (0.12.11 available)
  path_provider 2.0.2 (2.0.3 available)
  platform 3.0.0 (3.0.2 available)
  test_api 0.4.2 (0.4.3 available)
  win32 2.2.5 (2.2.9 available)
Changed 3 dependencies!

cloud_firestore позволяет получить доступ к хранилищу данных Cloud Firestore.

$ flutter pub add provider
Resolving dependencies...
  async 2.8.1 (2.8.2 available)
  matcher 0.12.10 (0.12.11 available)
+ nested 1.0.0
  path_provider 2.0.2 (2.0.3 available)
  platform 3.0.0 (3.0.2 available)
+ provider 6.0.0
  test_api 0.4.2 (0.4.3 available)
  win32 2.2.5 (2.2.9 available)
Changed 2 dependencies!

Хотя вы добавили необходимые пакеты, вам также необходимо настроить проекты iOS, Android, macOS и Web runner для надлежащего использования Firebase. Вы также с помощью provider пакет , который позволит отделить бизнес - логику от логики отображения.

Настроить iOS

  1. В Firebase консоли выберите Обзор проекта в левой навигационной панели, и нажмите кнопку IOS под Начните с добавлением Firebase к вашему приложению.

Вы должны увидеть следующий диалог:

c42139f18fb9a2ee.png

  1. Важное значение для обеспечения является IOS расслоения ID. Вы получите идентификатор пакета, выполнив следующие три шага.
  1. В инструменте командной строки перейдите в каталог верхнего уровня вашего приложения Flutter.
  2. Выполните команду open ios/Runner.xcworkspace открыть Xcode.
  1. В Xcode, выберите Runner верхнего уровня в левой панели, а затем выберите Runner под Targets, чтобы показать вкладку Общие в правой панели, как показано на рисунке. Скопируйте значение Bundle Identifier.

9d67acd88c718763.png

  1. Вернитесь в диалоговое окно Firebase, вставить скопированный Bundle Identifier в расслоением ID поля IOS и нажмите Зарегистрировать App.
  1. Продолжая Firebase, следуйте инструкциям , чтобы загрузить файл конфигурации GoogleService-Info.plist .
  2. Вернитесь в Xcode. Обратите внимание , что дорожка имеет вложенную также называется бегунка ( как показано в предыдущем изображении).
  3. Перетащите GoogleService-Info.plist файл (который вы только что скачали) в эту Runner вложенной.
  4. В появившемся диалоговом окне в Xcode, нажмите кнопку Готово.
  5. Не стесняйтесь закрыть Xcode на этом этапе, так как в дальнейшем это не обязательно.
  6. Вернитесь в консоль Firebase. На этапе установки, нажмите кнопку Далее, пропустите оставшиеся шаги и вернуться на главную страницу консоли Firebase.

Вы закончили настройку приложения Flutter для iOS. Для более подробной информации, пожалуйста, см документации по установке FlutterFire IOS .

Настроить Android

  1. В Firebase консоли выберите Обзор проекта в левой навигационной панели, и нажмите на кнопку Android под Начните с добавлением Firebase к вашему приложению.

Вы должны увидеть следующий диалог: 8254fc299e82f528.png

  1. Важное значение для обеспечения этого имя Android пакета. Вы получите имя пакета, когда выполните следующие два шага:
  1. В каталоге приложения Flutter, откройте файл android/app/src/main/AndroidManifest.xml .
  2. В manifest элемента, найти значение строки package атрибута. Это значение является именем Android пакета (что - то вроде com.yourcompany.yourproject ). Скопируйте это значение.
  3. В диалоговом окне Firebase, вставьте скопированное имя пакета в поле Android имени пакета.
  4. Вам не нужен Отладочный сертификат для подписи SHA-1 для этого codelab. Оставьте это поле пустым.
  5. Выберите Зарегистрировать приложение.
  6. Продолжая Firebase, следуйте инструкциям , чтобы загрузить файл конфигурации google-services.json .
  7. Перейти в каталог приложения Flutter, и переместить google-services.json файл (который вы только что скачали) в android/app каталога.
  8. Вернувшись в консоль Firebase, пропустите оставшиеся шаги и вернитесь на главную страницу консоли Firebase.
  9. Корректировать android/build.gradle , чтобы добавить google-services плагин зависимости:

android / build.gradle

dependencies {
        classpath 'com.android.tools.build:gradle:4.1.0'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath 'com.google.gms:google-services:4.3.5'  // new
}
  1. Редактировать ваш android/app/build.gradle , чтобы позволить google-services плагин:

Android / приложение / build.gradle

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
apply plugin: 'com.google.gms.google-services'  // new
  1. Firebase требует, чтобы Multidex был включен, и один из способов сделать это - установить минимальный поддерживаемый SDK на 21 или выше. Отредактируйте ваш android/app/build.gradle обновить minSdkVersion :

Android / приложение / build.gradle

defaultConfig {
    applicationId "com.example.gtk_flutter"
    minSdkVersion 21  // Updated
    targetSdkVersion 30
    versionCode flutterVersionCode.toInteger()
    versionName flutterVersionName
}

Вы закончили настройку приложения Flutter для Android. Для более подробной информации, пожалуйста, см документации по установке FlutterFire Android .

Настроить для Интернета

  1. В Firebase консоли выберите Обзор проекта в левой навигационной панели, и нажмите кнопку Web под Начните с добавлением Firebase к вашему приложению.

25b14deff9e589ce.png

  1. Дайте это приложение псевдоним, и нажмите на кнопку Зарегистрировать приложение. Мы собираемся оставить Firebase Hosting выключенным для этого руководства, так как мы будем запускать его только локально. Не стесняйтесь узнать больше о хостинге Firebase здесь. 9c697cc1b309c806.png
  2. Редактирование раздела тело вашего web/index.html файл следующим образом . Обязательно добавьте firebaseConfig данные из предыдущего шага.

web / index.html

<body>
  <script>
    if ('serviceWorker' in navigator) {
      window.addEventListener('flutter-first-frame', function () {
        navigator.serviceWorker.register('flutter_service_worker.js');
      });
    }
  </script>

  <!-- Add from here -->
  <script src="https://www.gstatic.com/firebasejs/7.20.0/firebase-app.js"></script>
  <script src="https://www.gstatic.com/firebasejs/7.20.0/firebase-auth.js"></script>
  <script src="https://www.gstatic.com/firebasejs/7.20.0/firebase-firestore.js"></script>
  <script>
    // Your web app's Firebase configuration
    var firebaseConfig = {
      // Replace this with your firebaseConfig
    };
    // Initialize Firebase
    firebase.initializeApp(firebaseConfig);
  </script>
  <!-- to here. -->

  <script src="main.dart.js" type="application/javascript"></script>
</body>

Вы закончили настраивать приложение Flutter для работы в Интернете. Для более подробной информации, пожалуйста, см документацию FlutterFire веб - установки .

Настроить macOS

Шаги настройки для macOS практически идентичны iOS. Мы будем повторно использовать файл конфигурации GoogleService-Info.plist от IOS шагов выше.

  1. Выполните команду open macos/Runner.xcworkspace открыть Xcode.
  1. Перетащите GoogleService-Info.plist файл в подпапку Runner. Это была создана в ступеньках Настройка IOS выше. c2b9229a605fd738.png
  2. В macos/Runner/DebugProfile.entitlements файл, добавьте com.apple.security.network.client право, и установить его на true . 8bee5665e35d3f34.png
  3. В macos/Runner/Release.entitlements файла, а также добавить com.apple.security.network.client право, и установить его на true . 41e2e23b7928546a.png
  4. Не стесняйтесь закрыть Xcode на этом этапе, так как в дальнейшем это не обязательно.

Вы закончили настройку приложения Flutter для macOS. Для более подробной информации, пожалуйста, см документации по установке FlutterFire MacOS , а также поддержка рабочего стола для Flutter страницы.

5. Добавьте вход пользователя (RSVP).

Теперь, когда вы добавили Firebase в приложение, вы можете настроить кнопку RSVP , который регистрирует людей , использующих Firebase аутентификации . Для встроенных приложений Android, iOS и Интернета есть предварительно созданные пакеты FirebaseUI Auth, но для Flutter вам потребуется создать эту возможность.

Проект, полученный вами на шаге 2, включал набор виджетов, реализующих пользовательский интерфейс для большей части потока аутентификации. Вы реализуете бизнес-логику для интеграции Firebase Authentication в приложение.

Бизнес-логика с провайдером

Вы собираетесь использовать provider пакет , чтобы сделать централизованное государство объект приложения доступна по всему дереву приложения виджетов флаттера. Начнем с того , изменения импорта в верхней части lib/main.dart :

lib / main.dart

import 'package:firebase_core/firebase_core.dart'; // new
import 'package:firebase_auth/firebase_auth.dart'; // new
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';           // new

import 'src/authentication.dart';                  // new
import 'src/widgets.dart';

В import линиях ввести Firebase сердечник и Auth, тянуть в provider пакета , который вы используете , чтобы сделать объект состояния приложения доступен через дерево виджетов, и включают в себя виджеты аутентификации от lib/src .

Это состояние приложения объект, ApplicationState , имеет две основные обязанности на этом этапе, но получат дополнительные обязанности , как вы добавите больше возможностей для применения в последующих стадиях. Первая обязанность заключается в том, чтобы инициализировать библиотеку Firebase с вызовом Firebase.initializeApp() , а затем есть обращение потока авторизации. Добавьте следующий класс до конца lib/main.dart :

lib / main.dart

class ApplicationState extends ChangeNotifier {
  ApplicationState() {
    init();
  }

  Future<void> init() async {
    await Firebase.initializeApp();

    FirebaseAuth.instance.userChanges().listen((user) {
      if (user != null) {
        _loginState = ApplicationLoginState.loggedIn;
      } else {
        _loginState = ApplicationLoginState.loggedOut;
      }
      notifyListeners();
    });
  }

  ApplicationLoginState _loginState = ApplicationLoginState.loggedOut;
  ApplicationLoginState get loginState => _loginState;

  String? _email;
  String? get email => _email;

  void startLoginFlow() {
    _loginState = ApplicationLoginState.emailAddress;
    notifyListeners();
  }

  void verifyEmail(
    String email,
    void Function(FirebaseAuthException e) errorCallback,
  ) async {
    try {
      var methods =
          await FirebaseAuth.instance.fetchSignInMethodsForEmail(email);
      if (methods.contains('password')) {
        _loginState = ApplicationLoginState.password;
      } else {
        _loginState = ApplicationLoginState.register;
      }
      _email = email;
      notifyListeners();
    } on FirebaseAuthException catch (e) {
      errorCallback(e);
    }
  }

  void signInWithEmailAndPassword(
    String email,
    String password,
    void Function(FirebaseAuthException e) errorCallback,
  ) async {
    try {
      await FirebaseAuth.instance.signInWithEmailAndPassword(
        email: email,
        password: password,
      );
    } on FirebaseAuthException catch (e) {
      errorCallback(e);
    }
  }

  void cancelRegistration() {
    _loginState = ApplicationLoginState.emailAddress;
    notifyListeners();
  }

  void registerAccount(String email, String displayName, String password,
      void Function(FirebaseAuthException e) errorCallback) async {
    try {
      var credential = await FirebaseAuth.instance
          .createUserWithEmailAndPassword(email: email, password: password);
      await credential.user!.updateProfile(displayName: displayName);
    } on FirebaseAuthException catch (e) {
      errorCallback(e);
    }
  }

  void signOut() {
    FirebaseAuth.instance.signOut();
  }
}

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

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

Интеграция потока аутентификации

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

lib / main.dart

void main() {
  // Modify from here
  runApp(
    ChangeNotifierProvider(
      create: (context) => ApplicationState(),
      builder: (context, _) => App(),
    ),
  );
  // to here.
}

Модификация main функции делает пакет поставщика , ответственный за создание экземпляра объекта состояния приложения , используя ChangeNotifierProvider виджет. Вы используете этот конкретный класс поставщика , так как состояние приложения объект расширяет ChangeNotifier и это позволяет provider пакета , чтобы знать , когда для повторного зависимых виджетов. И, наконец, интегрировать состояние приложения с Authentication путем обновления HomePage «сек build метод:

lib / main.dart

class HomePage extends StatelessWidget {
  HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Firebase Meetup'),
      ),
      body: ListView(
        children: <Widget>[
          Image.asset('assets/codelab.png'),
          SizedBox(height: 8),
          IconAndDetail(Icons.calendar_today, 'October 30'),
          IconAndDetail(Icons.location_city, 'San Francisco'),
          // Add from here
          Consumer<ApplicationState>(
            builder: (context, appState, _) => Authentication(
              email: appState.email,
              loginState: appState.loginState,
              startLoginFlow: appState.startLoginFlow,
              verifyEmail: appState.verifyEmail,
              signInWithEmailAndPassword: appState.signInWithEmailAndPassword,
              cancelRegistration: appState.cancelRegistration,
              registerAccount: appState.registerAccount,
              signOut: appState.signOut,
            ),
          ),
          // to here
          Divider(
            height: 8,
            thickness: 1,
            indent: 8,
            endIndent: 8,
            color: Colors.grey,
          ),
          Header("What we'll be doing"),
          Paragraph(
            'Join us for a day full of Firebase Workshops and Pizza!',
          ),
        ],
      ),
    );
  }
}

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

Тестирование процесса аутентификации

cdf2d25e436bd48d.png

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

2a2cd6d69d172369.png

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

e5e65065dba36b54.png

Обязательно попробуйте ввести короткий пароль (менее шести символов), чтобы проверить последовательность обработки ошибок. Если пользователь зарегистрирован, он вместо этого увидит пароль для.

fbb3ea35fb4f67a.png

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

4ed811a25b0cf816.png

Таким образом, вы реализовали поток аутентификации. Поздравляю!

6. Пишите сообщения в Cloud Firestore.

Знать, что приходят пользователи, - это здорово, но давайте дадим гостям чем-нибудь еще заняться в приложении. Что, если бы они могли оставлять сообщения в гостевой книге? Они могут рассказать, почему они рады приехать или с кем надеются встретиться.

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

Модель данных

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

7c20dc8424bb1d84.png

Добавить сообщения в Firestore

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

Во- первых, добавить импорт для cloud_firestore упаковки и dart:async .

lib / main.dart

import 'dart:async';                                    // new
import 'package:cloud_firestore/cloud_firestore.dart';  // new
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';

import 'src/authentication.dart';
import 'src/widgets.dart';

Для построения элементов пользовательского интерфейса из поля сообщения и кнопки отправки, добавить новый виджет Stateful GuestBook в нижней части lib/main.dart .

lib / main.dart

class GuestBook extends StatefulWidget {
  GuestBook({required this.addMessage});
  final FutureOr<void> Function(String message) addMessage;

  @override
  _GuestBookState createState() => _GuestBookState();
}

class _GuestBookState extends State<GuestBook> {
  final _formKey = GlobalKey<FormState>(debugLabel: '_GuestBookState');
  final _controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: Form(
        key: _formKey,
        child: Row(
          children: [
            Expanded(
              child: TextFormField(
                controller: _controller,
                decoration: const InputDecoration(
                  hintText: 'Leave a message',
                ),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Enter your message to continue';
                  }
                  return null;
                },
              ),
            ),
            SizedBox(width: 8),
            StyledButton(
              onPressed: () async {
                if (_formKey.currentState!.validate()) {
                  await widget.addMessage(_controller.text);
                  _controller.clear();
                }
              },
              child: Row(
                children: [
                  Icon(Icons.send),
                  SizedBox(width: 4),
                  Text('SEND'),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Здесь есть пара интересных мест. Во-первых, вы создаете экземпляр формы, чтобы upi мог подтвердить, что сообщение действительно имеет некоторый контент, и показать пользователю сообщение об ошибке, если его нет. Способ проверки формы включает в себя доступ к государственной форме за формой, и для этого вы используете GlobalKey . Для получения более подробной информации о ключах, и как использовать их, пожалуйста , см флаттера Widgets 101 эпизода «Когда использовать клавиши» .

Кроме того, обратите внимание, как виджеты выложенный, у вас есть Row , с TextFormField и StyledButton , которая сама по себе содержит Row . Также обратите внимание на TextFormField заворачивают в Expanded виджете, это вынуждает TextFormField принять любое дополнительное пространство в строке. Чтобы лучше понять , почему это необходимо, пожалуйста , прочитайте Понимание ограничений .

Теперь, когда у вас есть виджет, который позволяет пользователю вводить текст для добавления в гостевую книгу, вам нужно вывести его на экран. Чтобы сделать это, редактировать тело HomePage добавить следующие две строки в нижней части ListView «ы детей:

Header("What we'll be doing"),
Paragraph(
  'Join us for a day full of Firebase Workshops and Pizza!',
),
// Add the following two lines.
Header('Discussion'),
GuestBook(addMessage: (String message) => print(message)),

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

Предварительный просмотр приложения

Пользователь , нажав кнопку SEND вызовет фрагмент кода ниже. Он добавляет содержимое поля ввода сообщения в guestbook коллекции базы данных. В частности, addMessageToGuestBook метод добавляет содержание сообщения в новый документ (с автоматически генерируемым ID) в guestbook коллекции.

Обратите внимание , что FirebaseAuth.instance.currentUser.uid является ссылкой на автоматически генерируемой уникальный идентификатор , который Firebase Authentication дает для всех зарегистрированных пользователей.

Сделайте еще одно изменение в lib/main.dart файл. Добавьте addMessageToGuestBook метод. На следующем шаге вы объедините пользовательский интерфейс и эту возможность.

lib / main.dart

class ApplicationState extends ChangeNotifier {

  // Current content of ApplicationState elided ...

  // Add from here
  Future<DocumentReference> addMessageToGuestBook(String message) {
    if (_loginState != ApplicationLoginState.loggedIn) {
      throw Exception('Must be logged in');
    }

    return FirebaseFirestore.instance.collection('guestbook').add(<String, dynamic>{
      'text': message,
      'timestamp': DateTime.now().millisecondsSinceEpoch,
      'name': FirebaseAuth.instance.currentUser!.displayName,
      'userId': FirebaseAuth.instance.currentUser!.uid,
    });
  }
  // To here
}

Подключение пользовательского интерфейса к базе данных

У вас есть пользовательский интерфейс, в котором пользователь может ввести текст, который он хочет добавить в гостевую книгу, и у вас есть код для добавления записи в Cloud Firestore. Теперь все, что вам нужно сделать, это соединить их вместе. В lib/main.dart сделать следующее изменение HomePage виджета.

lib / main.dart

class HomePage extends StatelessWidget {
  HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Firebase Meetup'),
      ),
      body: ListView(
        children: <Widget>[
          Image.asset('assets/codelab.png'),
          SizedBox(height: 8),
          IconAndDetail(Icons.calendar_today, 'October 30'),
          IconAndDetail(Icons.location_city, 'San Francisco'),
          Consumer<ApplicationState>(
            builder: (context, appState, _) => Authentication(
              email: appState.email,
              loginState: appState.loginState,
              startLoginFlow: appState.startLoginFlow,
              verifyEmail: appState.verifyEmail,
              signInWithEmailAndPassword: appState.signInWithEmailAndPassword,
              cancelRegistration: appState.cancelRegistration,
              registerAccount: appState.registerAccount,
              signOut: appState.signOut,
            ),
          ),
          Divider(
            height: 8,
            thickness: 1,
            indent: 8,
            endIndent: 8,
            color: Colors.grey,
          ),
          Header("What we'll be doing"),
          Paragraph(
            'Join us for a day full of Firebase Workshops and Pizza!',
          ),
          // Modify from here
          Consumer<ApplicationState>(
            builder: (context, appState, _) => Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                if (appState.loginState == ApplicationLoginState.loggedIn) ...[
                  Header('Discussion'),
                  GuestBook(
                    addMessage: (String message) =>
                        appState.addMessageToGuestBook(message),
                  ),
                ],
              ],
            ),
          ),
          // To here.
        ],
      ),
    );
  }
}

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

Тестовая отправка сообщений

  1. Убедитесь, что вы вошли в приложение.
  2. Введите сообщение , такие как «Эй!», А затем нажмите кнопку SEND.

Это действие записывает сообщение в вашу базу данных Cloud Firestore. Однако вы еще не увидите это сообщение в своем реальном приложении Flutter, потому что вам все еще нужно реализовать получение данных. Вы сделаете это на следующем шаге.

Но вы можете увидеть только что добавленное сообщение в консоли Firebase.

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

Консоль Firebase

713870af0b3b63c.png

7. Прочтите сообщения.

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

Синхронизировать сообщения

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

Чуть выше GuestBook виджета следующего класса значения. Этот класс предоставляет структурированное представление данных, которые вы храните в Cloud Firestore.

lib / main.dart

class GuestBookMessage {
  GuestBookMessage({required this.name, required this.message});
  final String name;
  final String message;
}

В разделе ApplicationState где вы определяете состояние и добытчик, добавить следующие новые строки:

lib / main.dart

  ApplicationLoginState _loginState = ApplicationLoginState.loggedOut;
  ApplicationLoginState get loginState => _loginState;

  String? _email;
  String? get email => _email;

  // Add from here
  StreamSubscription<QuerySnapshot>? _guestBookSubscription;
  List<GuestBookMessage> _guestBookMessages = [];
  List<GuestBookMessage> get guestBookMessages => _guestBookMessages;
  // to here.

И , наконец, в разделе инициализации ApplicationState , добавьте следующие подписаться на запрос по сбору документов , когда пользователь входит в систему , и отказаться от подписки , когда они выйти из системы .

lib / main.dart

  Future<void> init() async {
    await Firebase.initializeApp();

    FirebaseAuth.instance.userChanges().listen((user) {
      if (user != null) {
        _loginState = ApplicationLoginState.loggedIn;
        // Add from here
        _guestBookSubscription = FirebaseFirestore.instance
            .collection('guestbook')
            .orderBy('timestamp', descending: true)
            .snapshots()
            .listen((snapshot) {
          _guestBookMessages = [];
          snapshot.docs.forEach((document) {
            _guestBookMessages.add(
              GuestBookMessage(
                name: document.data()['name'],
                message: document.data()['text'],
              ),
            );
          });
          notifyListeners();
        });
        // to here.
      } else {
        _loginState = ApplicationLoginState.loggedOut;
        // Add from here
        _guestBookMessages = [];
        _guestBookSubscription?.cancel();
        // to here.
      }
      notifyListeners();
    });
  }

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

Для получения дополнительной информации см документации Cloud Firestore .

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

lib / main.dart

class GuestBook extends StatefulWidget {
  // Modify the following line
  GuestBook({required this.addMessage, required this.messages});
  final FutureOr<void> Function(String message) addMessage;
  final List<GuestBookMessage> messages; // new

  @override
  _GuestBookState createState() => _GuestBookState();
}

Далее, мы подвергаем эту новую конфигурацию в _GuestBookState путем модификации build метод следующим образом .

lib / main.dart

class _GuestBookState extends State<GuestBook> {
  final _formKey = GlobalKey<FormState>(debugLabel: '_GuestBookState');
  final _controller = TextEditingController();

  @override
  // Modify from here
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        // to here.
        Padding(
          padding: const EdgeInsets.all(8.0),
          child: Form(
            key: _formKey,
            child: Row(
              children: [
                Expanded(
                  child: TextFormField(
                    controller: _controller,
                    decoration: const InputDecoration(
                      hintText: 'Leave a message',
                    ),
                    validator: (value) {
                      if (value == null || value.isEmpty) {
                        return 'Enter your message to continue';
                      }
                      return null;
                    },
                  ),
                ),
                SizedBox(width: 8),
                StyledButton(
                  onPressed: () async {
                    if (_formKey.currentState!.validate()) {
                      await widget.addMessage(_controller.text);
                      _controller.clear();
                    }
                  },
                  child: Row(
                    children: [
                      Icon(Icons.send),
                      SizedBox(width: 4),
                      Text('SEND'),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
        // Modify from here
        SizedBox(height: 8),
        for (var message in widget.messages)
          Paragraph('${message.name}: ${message.message}'),
        SizedBox(height: 8),
        // to here.
      ],
    );
  }
}

Вы завернуть предыдущее содержание метода сборки с Column виджетом, а затем в хвосте Column «s детей вы добавить коллекцию , чтобы создать новый Paragraph для каждого сообщения в списке сообщений.

Наконец, вам нужно обновить тело HomePage правильно построить GuestBook с новым messages параметра.

lib / main.dart

Consumer<ApplicationState>(
  builder: (context, appState, _) => Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      if (appState.loginState == ApplicationLoginState.loggedIn) ...[
        Header('Discussion'),
        GuestBook(
          addMessage: (String message) =>
              appState.addMessageToGuestBook(message),
          messages: appState.guestBookMessages, // new
        ),
      ],
    ],
  ),
),

Проверить синхронизацию сообщений

Cloud Firestore автоматически и мгновенно синхронизирует данные с клиентами, подписанными на базу данных.

  1. Сообщения, которые вы создали ранее в базе данных, должны отображаться в приложении. Не стесняйтесь писать новые сообщения; они должны появиться мгновенно.
  2. Если вы откроете свою рабочую область в нескольких окнах или вкладках, сообщения будут синхронизироваться в реальном времени между вкладками.
  3. (Необязательно) Вы можете попробовать вручную удалить, изменения или добавления новых сообщений непосредственно в разделе База данных консоли Firebase; любые изменения должны появиться в пользовательском интерфейсе.

Поздравляю! Вы читаете документы Cloud Firestore в своем приложении!

App р обзор

8. Установите основные правила безопасности.

Изначально вы настроили Cloud Firestore для использования тестового режима, что означает, что ваша база данных открыта для чтения и записи. Однако вам следует использовать тестовый режим только на самых ранних этапах разработки. Рекомендуется устанавливать правила безопасности для своей базы данных при разработке приложения. Безопасность должна быть неотъемлемой частью структуры и поведения вашего приложения.

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

Вы можете написать правила безопасности для Cloud Firestore в консоли Firebase:

  1. В разделе Develop Firebase консоли выберите базу данных, а затем выберите вкладку Правила (или нажмите здесь , чтобы перейти непосредственно к закладке Правила).
  2. Вы должны увидеть следующие правила безопасности по умолчанию, а также предупреждение о том, что правила являются общедоступными.

7767a2d2e64e7275.png

Определить коллекции

Сначала определите коллекции, в которые приложение записывает данные.

В match /databases/{database}/documents , определить коллекцию , которую вы хотите , чтобы обеспечить:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /guestbook/{entry} {
     // You'll add rules here in the next step.
  }
}

Добавить правила безопасности

Поскольку вы использовали UID аутентификации в качестве поля в каждом документе гостевой книги, вы можете получить UID аутентификации и убедиться, что любой, кто пытается выполнить запись в документ, имеет соответствующий UID аутентификации.

Добавьте правила чтения и записи в свой набор правил, как показано ниже:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /guestbook/{entry} {
      allow read: if request.auth.uid != null;
      allow write:
        if request.auth.uid == request.resource.data.userId;
    }
  }
}

Теперь в гостевой книге только зарегистрированные пользователи могут читать сообщения (любое сообщение!), Но только автор сообщения может редактировать сообщение.

Добавить правила проверки

Добавьте проверку данных, чтобы убедиться, что все ожидаемые поля присутствуют в документе:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /guestbook/{entry} {
      allow read: if request.auth.uid != null;
      allow write:
      if request.auth.uid == request.resource.data.userId
          && "name" in request.resource.data
          && "text" in request.resource.data
          && "timestamp" in request.resource.data;
    }
  }
}

9. Бонусный шаг: практикуйте то, что вы узнали.

Запишите статус ответа участника

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

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

В lib/main.dart , добавьте следующую строку в секцию аксессоров для того, чтобы код пользовательского интерфейса для взаимодействия с этим состоянием:

lib / main.dart

int _attendees = 0;
int get attendees => _attendees;

Attending _attending = Attending.unknown;
StreamSubscription<DocumentSnapshot>? _attendingSubscription;
Attending get attending => _attending;
set attending(Attending attending) {
  final userDoc = FirebaseFirestore.instance
      .collection('attendees')
      .doc(FirebaseAuth.instance.currentUser!.uid);
  if (attending == Attending.yes) {
    userDoc.set({'attending': true});
  } else {
    userDoc.set({'attending': false});
  }
}

Обновление ApplicationState «s init метод следующим образом :

lib / main.dart

  Future<void> init() async {
    await Firebase.initializeApp();

    // Add from here
    FirebaseFirestore.instance
        .collection('attendees')
        .where('attending', isEqualTo: true)
        .snapshots()
        .listen((snapshot) {
      _attendees = snapshot.docs.length;
      notifyListeners();
    });
    // To here

    FirebaseAuth.instance.userChanges().listen((user) {
      if (user != null) {
        _loginState = ApplicationLoginState.loggedIn;
        _guestBookSubscription = FirebaseFirestore.instance
            .collection('guestbook')
            .orderBy('timestamp', descending: true)
            .snapshots()
            .listen((snapshot) {
          _guestBookMessages = [];
          snapshot.docs.forEach((document) {
            _guestBookMessages.add(
              GuestBookMessage(
                name: document.data()['name'],
                message: document.data()['text'],
              ),
            );
          });
          notifyListeners();
        });
        // Add from here
        _attendingSubscription = FirebaseFirestore.instance
            .collection('attendees')
            .doc(user.uid)
            .snapshots()
            .listen((snapshot) {
          if (snapshot.data() != null) {
            if (snapshot.data()!['attending']) {
              _attending = Attending.yes;
            } else {
              _attending = Attending.no;
            }
          } else {
            _attending = Attending.unknown;
          }
          notifyListeners();
        });
        // to here
      } else {
        _loginState = ApplicationLoginState.loggedOut;
        _guestBookMessages = [];
        _guestBookSubscription?.cancel();
        _attendingSubscription?.cancel(); // new
      }
      notifyListeners();
    });
  }

Вышеупомянутый добавляет запрос с постоянной подпиской, чтобы узнать количество участников, и второй запрос, который активен только тогда, когда пользователь вошел в систему, чтобы узнать, присутствует ли пользователь. Затем добавьте следующую нумерацию после GuestBookMessage декларации:

lib / main.dart

enum Attending { yes, no, unknown }

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

lib / main.dart

class YesNoSelection extends StatelessWidget {
  const YesNoSelection({required this.state, required this.onSelection});
  final Attending state;
  final void Function(Attending selection) onSelection;

  @override
  Widget build(BuildContext context) {
    switch (state) {
      case Attending.yes:
        return Padding(
          padding: EdgeInsets.all(8.0),
          child: Row(
            children: [
              ElevatedButton(
                style: ElevatedButton.styleFrom(elevation: 0),
                onPressed: () => onSelection(Attending.yes),
                child: Text('YES'),
              ),
              SizedBox(width: 8),
              TextButton(
                onPressed: () => onSelection(Attending.no),
                child: Text('NO'),
              ),
            ],
          ),
        );
      case Attending.no:
        return Padding(
          padding: EdgeInsets.all(8.0),
          child: Row(
            children: [
              TextButton(
                onPressed: () => onSelection(Attending.yes),
                child: Text('YES'),
              ),
              SizedBox(width: 8),
              ElevatedButton(
                style: ElevatedButton.styleFrom(elevation: 0),
                onPressed: () => onSelection(Attending.no),
                child: Text('NO'),
              ),
            ],
          ),
        );
      default:
        return Padding(
          padding: EdgeInsets.all(8.0),
          child: Row(
            children: [
              StyledButton(
                onPressed: () => onSelection(Attending.yes),
                child: Text('YES'),
              ),
              SizedBox(width: 8),
              StyledButton(
                onPressed: () => onSelection(Attending.no),
                child: Text('NO'),
              ),
            ],
          ),
        );
    }
  }
}

Далее вам необходимо обновить HomePage метод сборки «s , чтобы воспользоваться YesNoSelection , что позволяет вошедшего в систему пользователя номинировать , если они посещают. Вы также будете отображать количество участников этого мероприятия.

lib / main.dart

Consumer<ApplicationState>(
  builder: (context, appState, _) => Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      // Add from here
      if (appState.attendees >= 2)
        Paragraph('${appState.attendees} people going')
      else if (appState.attendees == 1)
        Paragraph('1 person going')
      else
        Paragraph('No one going'),
      // To here.
      if (appState.loginState == ApplicationLoginState.loggedIn) ...[
        // Add from here
        YesNoSelection(
          state: appState.attending,
          onSelection: (attending) => appState.attending = attending,
        ),
        // To here.
        Header('Discussion'),
        GuestBook(
          addMessage: (String message) =>
              appState.addMessageToGuestBook(message),
          messages: appState.guestBookMessages,
        ),
      ],
    ],
  ),
),

Добавить правила

Поскольку у вас уже настроены некоторые правила, новые данные, которые вы добавляете с помощью кнопок, будут отклонены. Вам необходимо обновить правила , чтобы разрешить добавление к attendees коллекции.

Для attendees коллекции, так как вы использовали аутентификации UID в качестве имени документа, вы можете захватить его и убедитесь , что податель uid таким же , как в документе они пишут. Вы разрешите всем читать список участников (поскольку в нем нет личных данных), но только создатель должен иметь возможность обновлять его.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // ... //
    match /attendees/{userId} {
      allow read: if true;
      allow write: if request.auth.uid == userId;
    }
  }
}

Добавить правила проверки

Добавьте проверку данных, чтобы убедиться, что все ожидаемые поля присутствуют в документе:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // ... //
    match /attendees/{userId} {
      allow read: if true;
      allow write: if request.auth.uid == userId
          && "attending" in request.resource.data;

    }
  }
}

(Необязательно) Теперь вы можете просмотреть результаты нажатия кнопки. Перейдите на панель управления Cloud Firestore в консоли Firebase.

Предварительный просмотр приложения

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

Вы использовали Firebase для создания интерактивного веб-приложения в реальном времени!

Что мы покрыли

  • Проверка подлинности Firebase
  • Cloud Firestore
  • Правила безопасности Firebase

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

  • Хотите узнать больше о других продуктах Firebase? Может быть, вы хотите хранить файлы изображений, загружаемые пользователями? Или отправлять уведомления своим пользователям? Проверьте документацию Firebase . Хотите узнать больше о плагинах Flutter для Firebase? Проверьте FlutterFire для получения дополнительной информации.
  • Хотите узнать больше о Cloud Firestore? Может быть, вы хотите узнать о субколлекциях и транзакциях? Зайдем на веб - codelab Облако Firestore для codelab , который идет в большей глубины на облаке Firestore. Или проверить эту серию на YouTube , чтобы узнать Cloud Firestore !

Учить больше

Как прошло?

Будем рады вашему отзыву! Пожалуйста , заполните (очень) короткую форму здесь .