Использование CRUD-операций с базой данных Cloud Firestore в Flutter-приложениях

В этой статье мы рассмотрим, как интегрировать облачную базу данных в Flutter- приложение, и как использовать операции CRUD (создание, чтение, обновление и удаление записей).

Облачный сервис Cloud Firestore предоставляет доступ к предварительно настроенной базе данных NoSQL. Данная платформа обеспечивает хранение и синхронизацию данных и на стороне клиента, и на стороне сервера. Поддерживается автоматическое кэширование данных, что дает возможность использовать БД без подключения к интернету. Техническая основа Cloud Firestore – облачный сервис Google Cloud, поэтому подобную базу данных легко масштабировать. Итак, приступим.

Создание проекта Firebase

Для интеграции с Flutter- приложением нам надо создать новый проект. Перейдите в консоль Firebase и нажмите кнопку «Добавить проект».

Введите название проекта и нажмите кнопку «Продолжить».

На следующем шаге система спросит, хотите ли вы подключить аналитику Google Analytics. Аналитика нам в этот раз не потребуется, поскольку наш проект – учебный, поэтому мы выберем просто «Создать проект».

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

Подождите, пока проект будет создан; после завершения этой процедуры откроется панель управления базой данных Firebase.

Интеграция Firebase с Android, iOS и веб-приложениями

Хотя Flutter является кроссплатформенным решением, интеграция Firebase выполняется отдельно для каждой платформы. Flutter 2.0 поддерживает Android, iOS и веб-платформы, поэтому мы будем настраивать только Firebase.

Настройки для Android

Начнем с конфигурации Firebase для платформы Android. Выберите значок Android в панели управления Firebase.

Введите название создаваемого приложения, версию Android и хэш SHA-1 для сертификата безопасности. Нажмите на кнопку «Зарегистрировать приложение».

Скачайте файл google-services.json разместите его в директории android →app. Нажмите кнопку «Далее».

Следуя полученной инструкции, вставьте предоставленные фрагменты кода в свой проект и нажмите кнопку «Далее».

Конфигурация Firebase для Android успешно завершена. На заключительном этапе нажмите кнопку «Вернуться в консоль» для возвращения к панели управления.

Настройки для iOS

Для конфигурации Firebase под платформу iOS выполните шаги, указанные ниже.

Выберите значок iOS в панели управления Firebase.

Введите данные об операционной системе и название создаваемого приложения. Нажмите кнопку «Зарегистрировать приложение».

Скачайте файл GoogleService-Info.plist. Нажмите кнопку «Далее».

Откройте папку ios, используя Xcode, и перенесите скачанный файл в поддиректорию Runner. Убедитесь, что в диалоговом окне Runner указан в опции «Добавить к целям», затем нажмите кнопку «Завершить».

Шаги 3 и 4 можно пропустить, так как эти настройки будут автоматически созданы плагином Firebase, который мы добавим к Flutter. Нажмите кнопку «Вернуться в консоль» для возвращения к панели управления.

Настройки для работы с веб-приложениями

Настройте конфигурацию Firebase проекта для использования в веб-приложениях, выполнив приведенную ниже инструкцию.

Выберите значок Web-приложения в панели управления Firebase.

Введите название создаваемого приложения и нажмите кнопку «Зарегистрировать приложение».

Затем добавьте фрагменты кода для интеграции пакета Firebase SDK в создаваемое веб-приложение.

После этого нажмите кнопку «Вернуться в консоль» для возвращения к панели управления.

На этом процесс настройки Firebase для всех трех платформ завершен.

Начинаем работу над приложением

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

Обзор проекта

Мы создадим простое приложение для хранения заметок. Заметки можно будет просматривать, редактировать, удалять, добавлять новые.

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

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

Добавление Cloud Firestore

Подключите сервис Cloud Firestore, выбрав Firestore в левом меню и нажав кнопку «Создать базу данных».

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

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

Теперь выберите расположение Cloud Firestore и нажмите кнопку «Подключить».

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

Данные в базу мы добавим с помощью Flutter-приложения.

Создание Flutter-проекта

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

flutter create flutterfire_samples

После этого откройте проект, используя любой редактор кода. Если у вас установлен редактор VS Code, открыть проект можно следующей командой:

code flutterfire_samples

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

dart pub outdated --mode=null-safety

После проверки запустите миграцию:

dart migrate

Подробное руководство по миграции доступно здесь.

Интеграция базы Firebase в приложение Flutter

В нашем проекте мы будем использовать следующие плагины:

  • firebase_core – необходим для инициализации базы данных Firebase и подключения всех остальных плагинов;
  • cloud_firestore – нужен для операций с записями в базе данных Firebase.

Свежие версии этих плагинов поддерживают безопасную работу с пустыми ссылками.

Добавьте следующие строки в файл pubspec.yaml:

dependencies:
  firebase_core: ^1.0.1
  cloud_firestore: ^1.0.1

Установите пакеты, выполнив в командной строке следующую команду:

flutter pub get

Теперь откройте файл main.dart, находящийся в папке lib корневой директории. Измените его код на следующий:

import 'package:flutter/material.dart';
import 'package:flutterfire_samples/screens/login_screen.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'FlutterFire Samples',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.indigo,
        brightness: Brightness.dark,
      ),
      home: LoginScreen(),
    );
  }
}

Сделаем страницу авторизации LoginScreen виджетом с сохранением состояния. Определим метод _initializeFirebase() для инициализации базы данных приложения firebaseApp:

class LoginScreen extends StatefulWidget {
  @override
  _LoginScreenState createState() => _LoginScreenState();
}

class _LoginScreenState extends State<LoginScreen> {
  final FocusNode _uidFocusNode = FocusNode();

  Future<FirebaseApp> _initializeFirebase() async {
    FirebaseApp firebaseApp = await Firebase.initializeApp();

    return firebaseApp;
  }

  @override
  Widget build(BuildContext context) {
    // ...
  }
}

Этот код вызывает метод _initializeFirebase() из FutureBuilder, а после инициализации базы данных отображает на экране виджет с формой авторизации.

FutureBuilder(
  future: _initializeFirebase(),
  builder: (context, snapshot) {
    if (snapshot.hasError) {
      return Text('Ошибка инициализации базы данных);
    } else if (snapshot.connectionState ==
        ConnectionState.done) {
      return LoginForm(focusNode: _uidFocusNode);
    }
    return CircularProgressIndicator(
      valueColor: AlwaysStoppedAnimation<Color>(
        CustomColors.firebaseOrange,
      ),
    );
  },
)

Перед тем, как мы перейдем к доработке интерфейса, давайте посмотрим на структуру базы данных Firestore и определим методы для выполнения CRUD-операций.

Как устроена база данных Firebase

Для создания набора операций CRUD необходимо понять структуру базы данных Firestore. Облачные базы данных Cloud Firestore в основном состоят из коллекций, документов и полей (с парами «ключ-значение»). Коллекции могут состоять из набора документов, которые, в свою очередь, могут включать в себя подколлекции и пары «ключ-значение».

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

Подробнее о структуре хранения данных в Cloud Firestore можно узнать здесь.

Структура нашей базы данных выглядит следующим образом:

Перейдем к созданию CRUD операций на языке программирования Dart, который используется Flutter- приложениями. Создайте новый класс Database в файле database.dart.

Здесь мы сначала должны инициализировать базу FirebaseFirestore и определить главную коллекцию для сохранения наших данных.

import 'package:cloud_firestore/cloud_firestore.dart';

final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final CollectionReference _mainCollection = _firestore.collection('notes');

class Database {
  static String? userUid;

  // ...
}

Теперь переходим к созданию методов CRUD для класса Database. Начнем с операции write – запись.

Запись данных

Операция записи будет использоваться для добавления новых заметок в базу данных Firestore. Определим операцию записи методом addItem(), который передает название и описание заметки.

static Future<void> addItem({
  required String title,
  required String description,
}) async {
  DocumentReference documentReferencer =
      _mainCollection.doc(userUid).collection('items').doc();

  Map<String, dynamic> data = <String, dynamic>{
    "title": title,
    "description": description,
  };

  await documentReferencer
      .set(data)
      .whenComplete(() => print("Заметка добавлена в базу"))
      .catchError((e) => print(e));
}

Мы используем метод set() класса documentReferencer для записи новой информации в базу данных Firestore, и передаем данные в виде схемы.

Чтение данных

Для чтения записей в базе данных Firestore предусмотрены два класса – Future и Stream. Класс Future подходит, если данные считываются однократно. В нашем случае потребуется использование Stream, поскольку этот класс предусматривает автоматическую синхронизацию данных после внесения изменений в используемую базу.

static Stream<QuerySnapshot> readItems() {
  CollectionReference notesItemCollection =
      _mainCollection.doc(userUid).collection('items');

  return notesItemCollection.snapshots();
}

Обновление данных

Для обновления и редактирования можно передавать новые данные в виде схемы, используя метод update() в объекте documentReferencer. Для обновления конкретного документа в базе данных потребуется использование уникального идентификатора этого документа.

static Future<void> updateItem({
  required String title,
  required String description,
  required String docId,
}) async {
  DocumentReference documentReferencer =
      _mainCollection.doc(userUid).collection('items').doc(docId);

  Map<String, dynamic> data = <String, dynamic>{
    "title": title,
    "description": description,
  };

  await documentReferencer
      .update(data)
      .whenComplete(() => print("Заметка в базе успешно обновлена"))
      .catchError((e) => print(e));
}

Удаление данных

Для удаления заметки из базы данных можно использовать ее уникальный идентификатор. Данную операциюосуществляет метод delete() в объекте documentReferencer.

static Future<void> deleteItem({
  required String docId,
}) async {
  DocumentReference documentReferencer =
      _mainCollection.doc(userUid).collection('items').doc(docId);

  await documentReferencer
      .delete()
      .whenComplete(() => print('Заметка успешно удалена из базы'))
      .catchError((e) => print(e));
}

Приложение в действии

Поздравляем – вы успешно завершили работу по созданию набора CRUD-операций в Flutter- приложении, которое использует облачную базу данных Cloud Firestore.

Основные возможности приложения представлены на изображении, приведенном ниже.

Заключение

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

Официальной документацией сервиса занимается FlutterFire. Все материалы доступны здесь.

Исходный код приложения можно получить в репозитории GitHub.

Данная публикация является переводом статьи «CRUD operations using Firebase Cloud Firestore and Flutter» , подготовленная редакцией проекта.

Меню