1. Обзор
В этой лабораторной работе вы узнаете, как интегрировать Firebase Data Connect с базой данных Cloud SQL для создания приложения для просмотра фильмов на iOS с использованием SwiftUI.
Вы узнаете, как подключить свое iOS-приложение к базе данных Cloud SQL с помощью Firebase Data Connect, что обеспечит бесперебойную синхронизацию данных для обзоров фильмов.
К концу этой лабораторной работы у вас будет функциональное приложение для iOS, позволяющее пользователям просматривать фильмы и добавлять их в избранное. Все это будет работать на базе базы данных Cloud SQL с использованием возможностей Firebase Data Connect.
Чему вы научитесь
В этой лабораторной работе вы научитесь:
- Настройте Firebase Data Connect, используя набор эмуляторов Firebase, чтобы ускорить обработку данных.
- Разработайте схему базы данных с использованием Data Connect и GraphQL .
- Создайте типобезопасный Swift SDK из схемы вашей базы данных и добавьте его в приложение Swift.
- Реализуйте аутентификацию пользователей и интегрируйте ее с Firebase Data Connect, чтобы защитить данные ваших пользователей.
- Извлекайте, обновляйте, удаляйте и управляйте данными в Cloud SQL с помощью запросов и мутаций на основе GraphQL.
- (Необязательно) Разверните службу Data Connect в рабочей среде.
Предпосылки
- Последняя версия Xcode
- Пример кода для практического занятия. Вы загрузите пример кода на одном из первых этапов практического занятия.
2. Настройте пример проекта
Создать проект Firebase
- Войдите в консоль Firebase, используя свою учетную запись Google.
- Нажмите кнопку, чтобы создать новый проект, а затем введите название проекта (например,
Friendly Flix
). - Нажмите «Продолжить» .
- При появлении соответствующего запроса ознакомьтесь с условиями Firebase и примите их, а затем нажмите кнопку «Продолжить» .
- (Необязательно) Включите помощь ИИ в консоли Firebase (так называемая «Gemini в Firebase»).
- Для этой лабораторной работы вам не понадобится Google Analytics, поэтому отключите опцию Google Analytics.
- Нажмите «Создать проект» , дождитесь завершения подготовки проекта, а затем нажмите «Продолжить» .
Загрузите код
Выполните следующую команду, чтобы клонировать пример кода для этой лабораторной работы. Это создаст на вашем компьютере каталог с именем codelab-dataconnect-ios
:
git clone https://github.com/FirebaseExtended/codelab-dataconnect-ios`
Если на вашем компьютере нет git, вы также можете загрузить код непосредственно с GitHub.
Добавить конфигурацию Firebase
Firebase SDK использует файл конфигурации для подключения к вашему проекту Firebase. На платформах Apple этот файл называется GoogleServices-Info.plist
. На этом этапе вам нужно скачать файл конфигурации и добавить его в свой проект Xcode.
- В консоли Firebase выберите Обзор проекта в левой навигационной панели.
- Нажмите кнопку iOS+ , чтобы выбрать платформу. При запросе идентификатора пакета Apple используйте
com.google.firebase.samples.FriendlyFlix
- Нажмите «Зарегистрировать приложение» и следуйте инструкциям по загрузке файла
GoogleServices-Info.plist
. - Переместите загруженный файл в каталог
start/FriendlyFlix/app/FriendlyFlix/FriendlyFlix/
кода, который вы только что скачали, заменив существующий файлGoogleServices-Info.plist
. - Затем нажмите кнопку «Далее» несколько раз, чтобы завершить проект по настройке в консоли Firebase (вам не нужно добавлять SDK в приложение, так как это уже сделано в начальном проекте).
- Наконец, нажмите «Продолжить в консоли» , чтобы завершить процесс настройки.
3. Настройте подключение к данным
Установка
Автоматическая установка
Выполните следующую команду в каталоге codelab-dataconnect-ios/FriendlyFlix
:
curl -sL https://firebase.tools/dataconnect | bash
Этот скрипт пытается настроить среду разработки и запустить браузерную IDE. Эта IDE предоставляет инструменты, включая предустановленное расширение VS Code, которые помогут вам управлять схемой, определять запросы и мутации для использования в вашем приложении, а также генерировать строго типизированные SDK.
После запуска скрипта VS Code должен открыться автоматически.
После того, как вы сделаете это один раз, вы можете запустить VS Code, запустив VS Code в локальном каталоге:
code .
Ручная установка
- Установить Visual Studio Code
- Установить Node.js
- В VS Code откройте каталог
codelab-dataconnect-ios/FriendlyFlix
. - Установите расширение Firebase Data Connect из Visual Studio Code Marketplace .
Инициализируйте Data Connect в проекте
На левой панели щелкните значок Firebase, чтобы открыть пользовательский интерфейс расширения Data Connect VS Code.
- Нажмите кнопку «Войти через Google» . Откроется окно браузера; следуйте инструкциям, чтобы войти в расширение, используя свою учётную запись Google.
- Нажмите кнопку Подключить проект Firebase и выберите проект, который вы создали ранее в консоли.
- Нажмите кнопку «Запустить firebase init» и следуйте инструкциям во встроенном терминале.
Настроить генерацию SDK
После нажатия кнопки «Run firebase init» расширение Firebase Data Connect должно инициализировать для вас каталог dataconnect
.
В VS Code откройте файл dataconnect/connector/connector.yaml
, и вы найдете конфигурацию по умолчанию.
Обновите конфигурацию и используйте следующие настройки, чтобы сгенерированный код работал с этой лабораторной работой. В частности, убедитесь, что для параметра connectorId
задано значение friendly-flix
, а для пакета Swift — FriendlyFlixSDK
.
connectorId: "friendly-flix"
generate:
swiftSdk:
outputDir: "../../app"
package: "FriendlyFlixSDK"
observablePublisher: observableMacro
Вот что означают эти настройки:
-
connectorId
— уникальное имя данного коннектора. -
outputDir
— путь к месту сохранения сгенерированного Data Connect SDK. Этот путь указывается относительно каталога, содержащего файлconnector.yaml
. -
package
— имя пакета, которое будет использоваться для сгенерированного пакета Swift.
После сохранения этого файла Firebase Data Connect сгенерирует для вас пакет Swift с именем FriendlyFlixSDK
и поместит его рядом с папкой проекта FriendlyFlix
.
Запустите эмуляторы Firebase
В VS Code переключитесь на представление Firebase , а затем нажмите кнопку Запустить эмуляторы .
Это запустит эмулятор Firebase во встроенном терминале. Вывод должен выглядеть примерно так:
npx -y firebase-tools@latest emulators:start --project <your-project-id>
Добавьте сгенерированный пакет в ваше приложение Swift.
- Откройте
FriendlyFlix/app/FriendlyFlix/FriendlyFlix.xcodeproj
в Xcode. - Выберите Файл > Добавить зависимости пакета...
- Нажмите «Добавить локальный...» , затем добавьте пакет
FriendlyFlixSDK
из папкиFriendlyFlix/app
- Подождите, пока Xcode разрешит зависимости пакетов.
- В диалоговом окне «Выбор продуктов пакета для FriendlyFlixSDK» выберите
FriendlyFlix
в качестве целевого объекта и нажмите «Добавить пакет» .
Настройте приложение iOS для использования локального эмулятора
- Откройте
FriendlyFlixApp.swift
. (Можно нажать CMD + Shift + O, чтобы открыть диалоговое окно быстрого открытия , а затем ввести «FriendlyFlixApp», чтобы быстро найти файл.) - Импортируйте Firebase, Firebase Auth, Firebase Data Connect и сгенерированный SDK для вашей схемы.
- В инициализаторе настройте Firebase.
- Убедитесь, что DataConnect и Firebase Auth используют локальный эмулятор.
import SwiftUI
import os
import Firebase
import FirebaseAuth
import FriendlyFlixSDK
import FirebaseDataConnect
@main
struct FriendlyFlixApp: App {
...
init() {
FirebaseApp.configure()
if useEmulator {
DataConnect.friendlyFlixConnector.useEmulator(port: 9399)
Auth.auth().useEmulator(withHost: "localhost", port: 9099)
}
authenticationService = AuthenticationService()
}
...
}
- В раскрывающемся списке «Назначение» выберите симулятор iOS.
- Нажмите CMD+R (или щелкните кнопку « Выполнить ») в Xcode, чтобы запустить приложение на симуляторе.
4. Определите схему и предварительно заполните базу данных.
В этом разделе вы определите структуру и связи между ключевыми сущностями приложения для просмотра фильмов в схеме. Такие сущности, как Movie
, MovieMetaData
и другие, сопоставляются с таблицами базы данных, а связи устанавливаются с помощью директив схемы Firebase Data Connect и GraphQL.
Основные сущности и отношения
Модель данных для этого приложения для отслеживания фильмов состоит из нескольких сущностей, которые вы создадите в ходе этой лабораторной работы. Сначала вы создадите основные сущности, а затем, по мере реализации новых функций, будете добавлять необходимые для них сущности.
На этом этапе вы создадите типы Movie
и MovieMetadata
.
Фильм
Тип Movie
определяет основную структуру объекта «Фильм», включая такие поля, как title
, genre
, releaseYear
и rating
.
В VS Code добавьте определение типа Movie
в dataconnect/schema/schema.gql
:
type Movie @table {
id: UUID! @default(expr: "uuidV4()")
title: String!
imageUrl: String!
releaseYear: Int
genre: String
rating: Float
description: String
tags: [String]
}
MovieMetadata
Тип MovieMetadata
устанавливает связь «один к одному» с типом Movie
. Он включает дополнительные данные, например, данные о режиссёре фильма.
Добавьте определение таблицы MovieMetadata
в файл dataconnect/schema/schema.gql
:
type MovieMetadata @table {
movie: Movie! @ref
director: String
}
Автоматически сгенерированные поля и значения по умолчанию
Схема использует выражения вроде @default(expr: "uuidV4()")
для автоматической генерации уникальных идентификаторов и временных меток. Например, поле id
в типе Movie
автоматически заполняется UUID при создании новой записи.
Вставьте фиктивные данные для фильмов и метаданных фильмов
Определив схему, вы теперь можете предварительно заполнить базу данных фиктивными данными для тестирования.
- В Finder скопируйте
finish/FriendlyFlix/dataconnect/moviedata_insert.gql
в папкуstart/FriendlyFlix/dataconnect
. - В VS Code откройте
dataconnect/moviedata_insert.gql
. - Убедитесь, что эмуляторы в расширении Firebase Data Connect запущены.
- В верхней части файла должна появиться кнопка «Запустить (локально)» . Нажмите её, чтобы вставить данные макета фильма в базу данных.
- Проверьте терминал Data Connect Execution, чтобы убедиться, что данные были успешно добавлены.
Имея данные на месте, перейдите к следующему шагу, чтобы научиться создавать запросы в Data Connect.
5. Извлечение и отображение фильмов
В этом разделе вы реализуете функцию отображения списка фильмов.
Сначала вы узнаете, как создать запрос, который извлекает все фильмы из таблицы movies
. Firebase Data Connect генерирует код для типобезопасного SDK, который затем можно использовать для выполнения запроса и отображения извлеченных фильмов в пользовательском интерфейсе вашего приложения.
Определить запрос ListMovies
Запросы в Firebase Data Connect пишутся на языке GraphQL, что позволяет указать, какие поля следует извлекать. В FriendlyFlix экраны, на которых отображаются фильмы, должны содержать следующие поля: title
, description
, releaseYear
, rating
и imageUrl
. Кроме того, поскольку это приложение SwiftUI, вам понадобится id
для идентификации представления SwiftUI.
В VS Code откройте файл dataconnect/connector/queries.gql
и добавьте запрос ListMovies
:
query ListMovies @auth(level: PUBLIC) {
movies {
id
title
imageUrl
releaseYear
genre
rating
tags
description
}
}
Чтобы протестировать новый запрос, нажмите кнопку «Выполнить (локально)» , чтобы выполнить его к локальной базе данных. Список фильмов из базы данных должен отобразиться в разделе «Результаты» терминала Data Connect Execution.
Подключите запрос ListMovies к главному экрану приложения.
Теперь, когда вы протестировали запрос в эмуляторе Data Connect, вы можете вызвать запрос из своего приложения.
При сохранении queries.gql
Firebase Data Connect генерирует код, соответствующий запросу ListMovies
в пакете FriendlyFlixSDK
.
В Xcode откройте Movie+DataConnect.swift
и добавьте следующий код для сопоставления ListMoviesQuery.Data.Movie
с Movie
:
import FirebaseDataConnect
import FriendlyFlixSDK
extension Movie {
init(from: ListMoviesQuery.Data.Movie) {
id = from.id
title = from.title
description = from.description ?? ""
releaseYear = from.releaseYear
rating = from.rating
imageUrl = from.imageUrl
}
}
Откройте файл HomeScreen.swift
и обновите его, используя следующий фрагмент кода.
import SwiftUI
import FirebaseDataConnect
import FriendlyFlixSDK
struct HomeScreen: View {
...
private var connector = DataConnect.friendlyFlixConnector
let heroMoviesRef: QueryRefObservation<ListMoviesQuery.Data, ListMoviesQuery.Variables>
init() {
heroMoviesRef = connector.listMoviesQuery.ref()
}
}
extension HomeScreen {
...
private var heroMovies: [Movie] {
heroMoviesRef.data?.movies.map(Movie.init) ?? []
}
private var topMovies: [Movie] {
heroMoviesRef.data?.movies.map(Movie.init) ?? []
}
private var watchList: [Movie] {
heroMoviesRef.data?.movies.map(Movie.init) ?? []
}
...
}
Запрос |
Запустите приложение
В Xcode нажмите кнопку «Запустить» , чтобы запустить приложение в iOS Simulator.
После запуска приложения вы увидите примерно такой экран:
Вы могли заметить, что во всех разделах приложения (раздел «Главные герои», «Лучшие фильмы» и «Список просмотра») отображается один и тот же список. Это связано с тем, что вы используете один и тот же запрос для всех этих представлений. В следующих разделах вы реализуете пользовательские запросы. |
6. Отображение главных героев и лучших фильмов
На этом этапе вам предстоит обновить способ отображения фильмов в главном разделе (это заметная карусель в верхней части главного экрана), а также в разделе лучших фильмов ниже.
В настоящее время запрос ListMovies извлекает все фильмы. Чтобы оптимизировать отображение этих разделов, ограничьте количество фильмов, возвращаемых каждым запросом. Текущая реализация запроса ListMovies
пока не предлагает встроенной поддержки ограничения результатов. Добавление поддержки ограничения и упорядочивания — задача, которую вы добавите в этом разделе.
Улучшить запрос ListMovies
Откройте queries.gql
и обновите ListMovies
следующим образом, чтобы добавить поддержку упорядочивания и ограничения:
query ListMovies(
$orderByRating: OrderDirection
$orderByReleaseYear: OrderDirection
$limit: Int
) @auth(level: PUBLIC) {
movies(
orderBy: [{ rating: $orderByRating }, { releaseYear: $orderByReleaseYear }]
limit: $limit
) {
id
title
description
releaseYear
rating
imageUrl
}
}
Это позволит вам ограничить количество фильмов, возвращаемых запросом, и упорядочить результаты как по рейтингу, так и по году выпуска.
После сохранения файла Firebase Data Connect автоматически сгенерирует код в FriendlyFlixSDK
. На следующем этапе вы можете обновить код в HomeScreen.swift
, чтобы использовать эти дополнительные функции.
Используйте расширенный запрос в пользовательском интерфейсе
Вернитесь в Xcode, чтобы внести необходимые изменения в HomeScreen.swift
.
Сначала обновите heroMoviesRef
, чтобы получить 3 последних выпущенных фильма:
struct HomeScreen {
...
init() {
heroMoviesRef = connector.listMoviesQuery
.ref { optionalVars in
optionalVars.limit = 3
optionalVars.orderByReleaseYear = .DESC
}
}
}
Затем настройте еще один запрос для лучших фильмов и установите фильтр на 5 фильмов с самым высоким рейтингом:
struct HomeScreen {
...
let topMoviesRef: QueryRefObservation<ListMoviesQuery.Data, ListMoviesQuery.Variables>
init() {
heroMoviesRef = ...
topMoviesRef = connector.listMoviesQuery
.ref { optionalVars in
optionalVars.limit = 5
optionalVars.orderByRating = .DESC
}
}
}
Наконец, обновите вычисляемое свойство, которое связывает результат этого запроса с пользовательским интерфейсом:
extension HomeScreen {
...
private var topMovies: [Movie] {
topMoviesRef.data?.movies.map(Movie.init) ?? []
}
}
Посмотрите на это в действии
Запустите приложение еще раз, чтобы увидеть 3 последних фильма в разделе «Герои» и 5 фильмов с самым высоким рейтингом в разделе «Лучшие фильмы»:
7. Отображение информации о фильме и актере
Теперь пользователь может просматривать фильмы. При нажатии на карточку фильма отображаются некоторые сведения о нём, но вы, возможно, заметили, что им не хватает некоторых... ну... подробностей!
Это связано с тем, что мы извлекли только столько сведений о каждом фильме, сколько было необходимо для отображения раздела о главных героях и раздела самых популярных фильмов: название фильма, краткое описание и URL-адрес изображения.
На странице описания фильма нам нужно отобразить больше информации о нём. В этом разделе вы улучшите приложение, чтобы оно могло отображать информацию об актёрах фильма и отзывы на странице описания.
Для этого вам нужно будет сделать несколько вещей:
- Улучшить схему поддержки киноактеров и рецензий
- Напишите запросы Firebase Data Connect для получения информации о заданном фильме.
- Отображение результатов на экране сведений о фильме
Улучшить схему
В VS Code откройте dataconnect/schema/schema.gql
и добавьте определения схемы для Actor
и MovieActor
.
## Actors
## An actor can participate in multiple movies; movies can have multiple actors
## Movie - Actors (or vice versa) is a many to many relationship
type Actor @table {
id: UUID!
imageUrl: String!
name: String! @col(name: "name", dataType: "varchar(30)")
}
## Join table for many-to-many relationship for movies and actors
## The 'key' param signifies the primary key(s) of this table
## In this case, the keys are [movieId, actorId], the generated fields of the reference types [movie, actor]
type MovieActor @table(key: ["movie", "actor"]) {
## @ref creates a field in the current table (MovieActor) that holds the primary key of the referenced type
## In this case, @ref(fields: "id") is implied
movie: Movie!
## movieId: UUID! <- this is created by the implied @ref, see: implicit.gql
actor: Actor!
## actorId: UUID! <- this is created by the implied @ref, see: implicit.gql
role: String! ## "main" or "supporting"
}
Добавить фиктивные данные для актеров
После обновления схемы вы теперь можете заполнить базу данных дополнительными тестовыми данными для тестирования.
- В Finder скопируйте
finish/FriendlyFlix/dataconnect/moviededetails_insert.gql
в папкуstart/FriendlyFlix/dataconnect
. - В VS Code откройте
dataconnect/moviededetails_insert.gql
. - Убедитесь, что эмуляторы в расширении Firebase Data Connect запущены.
- В верхней части файла должна появиться кнопка «Запустить (локально)» . Нажмите её, чтобы вставить данные макета фильма в базу данных.
- Проверьте терминал Data Connect Execution, чтобы убедиться, что данные были успешно добавлены.
Имея данные на своем месте, перейдите к следующему шагу, чтобы определить запрос для получения сведений о фильме.
Определить запрос GetMovieById
В VS Code откройте файл dataconnect/connector/queries.gql
и добавьте запрос GetMovieById
:
## Get movie by id
query GetMovieById($id: UUID!) @auth(level: PUBLIC) {
movie(id: $id) {
id
title
imageUrl
releaseYear
genre
rating
description
tags
metadata: movieMetadatas_on_movie {
director
}
mainActors: actors_via_MovieActor(where: { role: { eq: "main" } }) {
id
name
imageUrl
}
supportingActors: actors_via_MovieActor(
where: { role: { eq: "supporting" } }
) {
id
name
imageUrl
}
}
}
Подключите запрос GetMovieById к MovieDetailsView
В Xcode откройте файл MovieDetailsView.swift
и обновите вычисляемое свойство movieDetails
в соответствии со следующим кодом:
import NukeUI
import SwiftUI
import FirebaseDataConnect
import FriendlyFlixSDK
@MainActor
struct MovieDetailsView: View {
private var movie: Movie
private var movieDetails: MovieDetails? {
DataConnect.friendlyFlixConnector
.getMovieByIdQuery
.ref(id: movie.id)
.data?.movie.map { movieDetails in
MovieDetails(
title: movieDetails.title,
description: movieDetails.description ?? "",
releaseYear: movieDetails.releaseYear,
rating: movieDetails.rating ?? 0,
imageUrl: movieDetails.imageUrl,
mainActors: movieDetails.mainActors.map { mainActor in
MovieActor(id: mainActor.id,
name: mainActor.name,
imageUrl: mainActor.imageUrl)
},
supportingActors: movieDetails.supportingActors.map{ supportingActor in
MovieActor(id: supportingActor.id,
name: supportingActor.name,
imageUrl: supportingActor.imageUrl)
},
reviews: []
)
}
}
public init(movie: Movie) {
self.movie = movie
}
}
Запустите приложение
В Xcode нажмите кнопку «Запустить» , чтобы запустить приложение в iOS Simulator.
После запуска приложения нажмите на карточку фильма, чтобы отобразить информацию о нём. Она должна выглядеть примерно так:
8. Реализуйте аутентификацию пользователей.
В настоящее время приложение предоставляет неперсонализированную информацию о фильмах и актёрах. На следующих этапах вы реализуете функции, связывающие данные с вошедшим в систему пользователем. Сначала вы позволите пользователям добавлять фильмы в свой личный список просмотра.
Прежде чем реализовать функцию списка наблюдения, необходимо установить личность пользователя. Для этого необходимо интегрировать аутентификацию Firebase, которая позволит пользователям входить в приложение.
Возможно, вы уже заметили кнопку аватара пользователя в правом верхнем углу главного экрана. Нажав на неё, вы попадёте на экран, где пользователи могут зарегистрироваться или войти в систему, используя свой адрес электронной почты и пароль.
После того как пользователь успешно войдет в систему, вашему приложению потребуется сохранить его основные данные, в первую очередь уникальный идентификатор пользователя и выбранное им имя пользователя.
Включить аутентификацию Firebase
В консоли Firebase вашего проекта перейдите в раздел «Аутентификация» и включите аутентификацию Firebase. Затем включите поставщика аутентификации по электронной почте и паролю.
В локальной папке проекта найдите firebase.json
и обновите его следующим образом, чтобы включить эмулятор аутентификации Firebase.
{
"emulators": {
"dataconnect": {
},
"auth": {
}
},
"dataconnect": {
"source": "dataconnect"
}
}
После этого необходимо остановить и перезапустить Firebase Emulator, чтобы изменения вступили в силу.
Реализовать обработчик аутентификации
В следующем разделе вы реализуете логику, связывающую аутентификацию пользователей с базой данных. Это включает в себя создание обработчика аутентификации, который отслеживает успешные входы в систему.
После аутентификации пользователя этот обработчик автоматически инициирует создание соответствующей учетной записи в вашей базе данных.
В Xcode откройте файл AuthenticationService.swift
и добавьте следующий код:
import Foundation
import Observation
import os
import FirebaseAuth
enum AuthenticationState {
case unauthenticated
case authenticating
case authenticated
}
@Observable
class AuthenticationService {
private let logger = Logger(subsystem: "FriendlyFlix", category: "auth")
var presentingAuthenticationDialog = false
var presentingAccountDialog = false
var authenticationState: AuthenticationState = .unauthenticated
var user: User?
private var authenticationListener: AuthStateDidChangeListenerHandle?
init() {
authenticationListener = Auth.auth().addStateDidChangeListener { auth, user in
if let user {
self.authenticationState = .authenticated
self.user = user
} else {
self.authenticationState = .unauthenticated
}
}
}
private var onSignUp: ((User) -> Void)?
public func onSignUp(_ action: @escaping (User) -> Void) {
onSignUp = action
}
func signInWithEmailPassword(email: String, password: String) async throws {
try await Auth.auth().signIn(withEmail: email, password: password)
authenticationState = .authenticated
}
func signUpWithEmailPassword(email: String, password: String) async throws {
try await Auth.auth().createUser(withEmail: email, password: password)
if let onSignUp, let user = Auth.auth().currentUser {
logger
.debug(
"User signed in \(user.displayName ?? "(no fullname)") with email \(user.email ?? "(no email)")"
)
onSignUp(user)
}
authenticationState = .authenticated
}
func signOut() throws {
try Auth.auth().signOut()
authenticationState = .unauthenticated
}
}
Это универсальный обработчик аутентификации, позволяющий использовать onSignUp
для регистрации замыкания, которое будет вызвано после входа пользователя в систему.
Внутри этого замыкания вы можете создать новую учётную запись пользователя в базе данных. Но прежде чем это сделать, необходимо создать мутацию, которая позволит создавать или обновлять новых пользователей в базе данных.
Добавить сущность «Пользователь» в схему
Тип User
определяет сущность пользователя. Пользователи могут взаимодействовать с фильмами, оставляя отзывы или добавляя фильмы в избранное.
В VS Code откройте файл dataconnect/schema/schema.gql
и добавьте следующее определение таблицы User
:
## Users
## A user can leave reviews for movies
## user-reviews is a one to many relationship, movie-reviews is a one to many relationship, movie:user is a many to many relationship
type User @table {
id: String! @col(name: "user_auth")
username: String! @col(name: "username", dataType: "varchar(50)")
}
Определить мутацию для вставки или обновления пользователя
В VS Code откройте файл dataconnect/connector/mutations.gql
и добавьте мутацию UpsertUser
:
mutation UpsertUser($username: String!) @auth(level: USER) {
user_upsert(
data: {
id_expr: "auth.uid"
username: $username
}
)
}
Создайте нового пользователя после успешного входа в систему.
В Xcode откройте FriendlyFlixApp.swift
и добавьте следующий код в инициализатор:
@main
struct FriendlyFlixApp: App {
...
init() {
...
authenticationService = AuthenticationService()
authenticationService?.onSignUp { user in
let userName = String(user.email?.split(separator: "@").first ?? "(unknown)")
Task {
try await DataConnect.friendlyFlixConnector
.upsertUserMutation.execute(username: userName)
}
}
}
var body: some Scene {
...
}
}
Этот код использует upsertUserMutation
Firebase Data Connect, сгенерированный для вставки нового пользователя (или обновления существующего пользователя с тем же идентификатором) всякий раз, когда пользователь успешно регистрируется с использованием аутентификации Firebase.
Посмотрите на это в действии
Чтобы проверить, работает ли это, сначала зарегистрируйтесь в приложении для iOS:
- Если вы этого не сделали, остановите и перезапустите эмулятор Firebase, чтобы убедиться, что эмулятор аутентификации Firebase запущен.
- В Xcode нажмите кнопку «Запустить» , чтобы запустить приложение в iOS Simulator.
- Нажмите на значок аватара в правом верхнем углу экрана.
- Перейдите на страницу регистрации и зарегистрируйтесь в приложении.
Затем выполните запрос к базе данных, чтобы убедиться, что приложение создало новую учетную запись пользователя:
- В VS Code откройте
dataconnect/schema/schema.gql
и нажмите Read data для сущностиUser
- Это создаст новый файл запроса с именем
User_read.gql
- Нажмите « Запустить локально», чтобы увидеть всех пользователей в таблице пользователей.
- На панели «Выполнение подключения к данным» вы теперь должны увидеть учетную запись пользователя, с которым вы только что зарегистрировались.
9. Управление любимыми фильмами
В этом разделе лабораторной работы вы реализуете взаимодействие с пользователем в приложении для просмотра фильмов, в частности, позволите пользователям управлять своими любимыми фильмами. Фильмы, добавленные в избранное, будут отображаться в списке просмотра приложения.
Улучшить схему для поддержки избранного
Тип FavoriteMovie
— это таблица, которая поддерживает связи типа «многие ко многим» между пользователями и их любимыми фильмами. Каждая таблица связывает User
с Movie
.
Скопируйте и вставьте фрагмент кода в файл dataconnect/schema/schema.gql
:
type FavoriteMovie
@table(name: "FavoriteMovies", singular: "favorite_movie", plural: "favorite_movies", key: ["user", "movie"]) {
## @ref is implicit
user: User!
movie: Movie!
}
Определить мутации для добавления и удаления избранных
Прежде чем приложение сможет отображать любимые фильмы пользователя, ему необходимо указать, какие из них являются его любимыми. Для этого сначала нужно добавить две мутации: чтобы добавить фильм в список любимых или удалить его из списка избранного, соответственно.
- В VS Code откройте
mutations.gql
вdataconnect/connector/mutations.gql
- Добавьте следующие мутации для обработки избранных фильмов:
## Add a movie to the user's favorites list
mutation AddFavoritedMovie($movieId: UUID!) @auth(level: USER) {
favorite_movie_upsert(data: { userId_expr: "auth.uid", movieId: $movieId })
}
## Remove a movie from the user's favorites list
mutation DeleteFavoritedMovie($movieId: UUID!) @auth(level: USER) {
favorite_movie_delete(key: { userId_expr: "auth.uid", movieId: $movieId })
}
Подключите мутации к пользовательскому интерфейсу вашего приложения
Пользователи могут добавить фильм в избранное, нажав на значок сердца на экране сведений о фильме.
Чтобы подключить только что созданные мутации к пользовательскому интерфейсу приложения, внесите следующие изменения в MovieCardView
:
- Импортируйте
FriendlyFlixSDK
и настройте коннектор.
import NukeUI
import os
import SwiftUI
import FirebaseDataConnect
import FriendlyFlixSDK
struct MovieCardView: View {
private let logger = Logger(subsystem: "FriendlyFlix", category: "moviecard")
@Environment(\.dismiss) private var dismiss
private var connector = DataConnect.friendlyFlixConnector
...
}
- Реализуйте метод
toggleFavourite
. Он будет вызываться каждый раз, когда пользователь нажимает на значок сердца вMovieCardView
:
struct MovieCardView {
...
private func toggleFavourite() {
Task {
if isFavourite {
let _ = try await connector.deleteFavoritedMovieMutation.execute(movieId: movie.id)
} else {
let _ = try await connector.addFavoritedMovieMutation.execute(movieId: movie.id)
}
}
}
}
Это обновит статус избранного текущего фильма в базе данных. Последний шаг, которого не хватает, — это обеспечение соответствующего отображения состояния пользовательского интерфейса.
Определите запрос, чтобы выяснить, отмечен ли фильм как избранный.
- В VS Code откройте
queries.gql
вdataconnect/connector
. - Добавьте следующий запрос, чтобы проверить, отмечен ли фильм как избранный:
query GetIfFavoritedMovie($movieId: UUID!) @auth(level: USER) {
favorite_movie(key: { userId_expr: "auth.uid", movieId: $movieId }) {
movieId
}
}
- В Xcode создайте ссылку на запрос
GetIfFavoritedMovie
и реализуйте вычисляемое свойство, которое определяет, отмечен ли фильм, показанный в этомMovieCardView
, как избранный для текущего пользователя.
struct MovieCardView: View {
...
public init(showDetails: Bool, movie: Movie) {
self.showDetails = showDetails
self.movie = movie
isFavouriteRef = connector.getIfFavoritedMovieQuery.ref(movieId: movie.id)
}
// MARK: - Favourite handling
private let isFavouriteRef: QueryRefObservation<
GetIfFavoritedMovieQuery.Data,
GetIfFavoritedMovieQuery.Variables
>
private var isFavourite: Bool {
isFavouriteRef.data?.favorite_movie?.movieId != nil
}
...
}
- Обновите код в
toggleFavourite
, чтобы запрос выполнялся при каждом нажатии кнопки пользователем. Это гарантирует, что вычисляемое свойствоisFavourite
всегда возвращает правильное значение.
private func toggleFavourite() {
Task {
if isFavourite {
...
}
let _ = try await isFavouriteRef.execute()
}
}
Получить любимые фильмы
В качестве последнего шага для этой функции вы реализуете извлечение любимых фильмов пользователя, чтобы он мог видеть их в своем списке просмотра.
- В VS Code откройте
queries.gql
вdataconnect/connector/queries.gql
и вставьте следующий запрос:
## Get favorite movies by user ID
query GetUserFavoriteMovies @auth(level: USER) {
user(id_expr: "auth.uid") {
favoriteMovies: favorite_movies_on_user {
movie {
id
title
genre
imageUrl
releaseYear
rating
description
}
}
}
}
Список любимых фильмов пользователя отображается на LibraryScreen
. Этот экран должен отображать данные только в том случае, если пользователь вошел в систему, поэтому сначала необходимо подключить состояние аутентификации экрана к AuthenticationService
приложения.
- Добавьте код для сопоставления
FavoriteMovieFavoriteMovies
сMovie
вMovie+DataConnect.swift
:
import FirebaseDataConnect
import FriendlyFlixSDK
extension Movie {
...
init(from: GetUserFavoriteMoviesQuery.Data.User.FavoriteMovieFavoriteMovies) {
id = from.movie.id
title = from.movie.title
description = from.movie.description ?? ""
releaseYear = from.movie.releaseYear
rating = from.movie.rating
imageUrl = from.movie.imageUrl
}
}
- В Xcode откройте
LibraryScreen
, затем обновитеisSignedIn
следующим образом:
struct LibraryScreen: View {
...
private var isSignedIn: Bool {
authenticationService.user != nil
}
}
- Затем импортируйте Firebase Data Connect и FriendlyFlixSDK и получите ссылку на запрос
GetUserFavoriteMovies
:
import SwiftUI
import FirebaseDataConnect
import FriendlyFlixSDK
struct LibraryScreen {
...
private var connector = DataConnect.friendlyFlixConnector
...
init() {
watchListRef = connector.getUserFavoriteMoviesQuery.ref()
}
private let watchListRef: QueryRefObservation<
GetUserFavoriteMoviesQuery.Data,
GetUserFavoriteMoviesQuery.Variables
>
private var watchList: [Movie] {
watchListRef.data?.user?.favoriteMovies.map(Movie.init) ?? []
}
...
}
- Убедитесь, что запрос
watchListRef
выполняется при появлении представления:
extension LibraryScreen: View {
var body: some View {
...
MovieListSection(namespace: namespace, title: "Watch List", movies: watchList)
.onAppear {
Task {
try await watchListRef.execute()
}
...
Посмотрите на это в действии
Теперь вы можете запустить приложение и опробовать только что добавленную функцию «Избранное». Обратите внимание на несколько моментов:
- Убедитесь, что эмулятор Firebase запущен.
- Убедитесь, что вы добавили фиктивные данные для фильмов и информацию о них.
- Убедитесь, что вы зарегистрировались как пользователь.
- В Xcode нажмите кнопку «Запустить» , чтобы запустить приложение в iOS Simulator.
- После запуска приложения нажмите на карточку фильма, чтобы отобразить подробную информацию о нем.
- Нажмите на значок сердца, чтобы добавить фильм в избранное. Сердце должно стать сплошным.
- Повторите это для нескольких фильмов.
- Перейдите на вкладку «Библиотека». Теперь вы увидите список всех фильмов, которые вы добавили в избранное.
10. Поздравления
Поздравляем! Вы успешно добавили Firebase Data Connect в приложение iOS! Теперь вы знаете основные шаги, необходимые для настройки Data Connect, создания запросов и мутаций, а также для аутентификации пользователей.
Необязательно: развернуть в производстве
До сих пор это приложение использовало только эмуляторы Firebase. Если вы хотите узнать, как развернуть это приложение в реальном проекте Firebase, перейдите к следующему шагу.
11. (Необязательно) Разверните свое приложение.
До сих пор это приложение было полностью локальным, все данные хранились в Firebase Emulator Suite. В этом разделе вы узнаете, как настроить проект Firebase для работы этого приложения в продакшене.
Включить аутентификацию Firebase
- В консоли Firebase перейдите в раздел Аутентификация и нажмите Начать .
- Перейдите на вкладку «Способ входа» .
- Выберите опцию «Электронная почта/Пароль» в разделе собственных поставщиков.
- Включите поставщика электронной почты/пароля, затем нажмите « Сохранить» .
Включить Firebase Data Connect
Важно: Если вы впервые развёртываете схему в своём проекте, в ходе этого процесса будет создан экземпляр Cloud SQL PostgreSQL, что может занять около 15 минут. Вы не сможете выполнить развёртывание, пока экземпляр Cloud SQL не будет готов и интегрирован с Firebase Data Connect.
1. В интерфейсе расширения Firebase Data Connect VS Code нажмите кнопку «Развернуть в рабочей среде» . 2. Возможно, потребуется проверить изменения схемы и одобрить потенциально деструктивные модификации. Вам будет предложено: — проверить изменения схемы с помощью firebase dataconnect:sql:diff
; — если вы удовлетворены изменениями, примените их с помощью потока, запущенного командой firebase dataconnect:sql:migrate
Ваш экземпляр Cloud SQL для PostgreSQL будет обновлён с учётом окончательной развёрнутой схемы и данных. Вы можете отслеживать статус обновления в консоли Firebase.
Теперь вы можете нажать кнопку «Запустить (Производство)» на панели Firebase Data Connect, как вы это делали с локальными эмуляторами, чтобы добавить данные в производственную среду.
Перед повторным запуском приложения iOS убедитесь, что оно подключено к производственному экземпляру вашего проекта:
- Откройте меню Продукт > Схема > Редактировать схему....
- В разделе «Выполнить» снимите флажок с аргумента запуска
-useEmulator YES
.