1. 總覽
本程式碼研究室將引導您整合 Firebase Data Connect 與 Cloud SQL 資料庫,以便使用 SwiftUI 建構適用於 iOS 的電影評論應用程式
您將瞭解如何使用 Firebase Data Connect 將 iOS 應用程式連結至 Cloud SQL 資料庫,以便順暢同步電影評論資料。
完成本程式碼研究室後,您將擁有一個功能齊全的 iOS 應用程式,可讓使用者瀏覽電影,並將電影標示為喜好項目,所有這些功能都由 Cloud SQL 資料庫提供支援,並運用 Firebase Data Connect 的強大功能。
課程內容
本程式碼研究室將說明如何:
- 設定 Firebase Data Connect,使用 Firebase Emulator 套件可加快處理時間。
- 使用 Data Connect 和 GraphQL設計資料庫結構定義。
- 從資料庫結構定義建立類型安全的 Swift SDK,然後將其新增至 Swift 應用程式。
- 實作使用者驗證,並與 Firebase Data Connect 整合,以保護使用者資料。
- 使用 GraphQL 提供的查詢和變異,擷取、更新、刪除及管理 Cloud SQL 中的資料。
- (選用) 將 Data Connect 服務部署至實際工作環境。
事前準備
- 最新版 Xcode
- 程式碼研究室的範例程式碼。您會在程式碼研究室的其中一個初步步驟中下載程式碼範例。
2. 設定範例專案
建立 Firebase 專案
- 使用 Google 帳戶登入 Firebase 主控台。
- 在 Firebase 控制台中,按一下「建立 Firebase 專案」。
- 輸入 Firebase 專案名稱 (例如「Friendly Flix」),然後按一下「Continue」。
- 系統可能會要求您為 Firebase 專案啟用 AI 輔助功能。在本程式碼研究室中,您的選擇不具影響。
- 系統可能會要求您啟用 Google Analytics。在本程式碼研究室中,您的選擇不具影響。
- 大約一分鐘後,Firebase 專案就會準備就緒。點選「繼續」。
下載程式碼
執行下列指令,複製這個程式碼研究室的範例程式碼。這會在電腦上建立名為 codelab-dataconnect-ios
的目錄:
git clone https://github.com/peterfriese/codelab-dataconnect-ios`
如果您的電腦上沒有 Git,也可以直接從 GitHub 下載程式碼。
新增 Firebase 設定
Firebase SDK 會使用設定檔連線至 Firebase 專案。在 Apple 平台上,這個檔案稱為 GoogleServices-Info.plist
。在這個步驟中,您將下載設定檔並將其新增至 Xcode 專案。
- 在 Firebase 控制台中,選取左側導覽面板中的「專案總覽」。
- 按一下「iOS+」按鈕,選取平台。系統提示您輸入 Apple 軟體包 ID 時,請輸入
com.google.firebase.samples.FriendlyFlix
- 按一下「註冊應用程式」,然後按照操作說明下載
GoogleServices-Info.plist
檔案。 - 將下載的檔案移至剛才下載的程式碼的
start/FriendlyFlix/app/FriendlyFlix/FriendlyFlix/
目錄,取代現有的GoogleServices-Info.plist
檔案。 - 接著按幾次「Next」,在 Firebase 控制台中完成設定專案 (您不需要將 SDK 新增至應用程式,因為這項操作已在入門專案中完成)。
- 最後,按一下「繼續前往控制台」,完成設定程序。
3. 設定 Data Connect
安裝
自動安裝
在 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
目錄。 - 前往 Visual Studio Code Marketplace 安裝 Firebase Data Connect 擴充功能。
在專案中初始化 Data Connect
在左側面板中,按一下 Firebase 圖示,開啟 Data Connect VS Code 擴充功能 UI
- 點選「使用 Google 帳戶登入」按鈕。瀏覽器視窗隨即開啟,請按照操作說明使用 Google 帳戶登入擴充功能。
- 按一下「連結 Firebase 專案」按鈕,然後選取您先前在控制台中建立的專案。
- 按一下「Run 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 會為您產生名為 FriendlyFlixSDK
的 Swift 套件,並將其放在 FriendlyFlix
專案資料夾旁。
啟動 Firebase 模擬器
在 VS Code 中切換至 Firebase 檢視畫面,然後按一下「Start emulators」按鈕。
系統就會在整合式終端機中啟動 Firebase Emulator。輸出內容應如下所示:
npx -y firebase-tools@latest emulators:start --project <your-project-id>
將產生的套件新增至 Swift 應用程式
- 在 Xcode 中開啟
FriendlyFlix/app/FriendlyFlix/FriendlyFlix.xcodeproj
- 依序選取「File」>「Add Package Dependencies...」。
- 按一下「Add Local...」,然後從
FriendlyFlix/app
資料夾新增FriendlyFlixSDK
套件 - 等待 Xcode 解析套件依附元件。
- 在「Choose Package Products for FriendlyFlixSDK」對話方塊中,選取
FriendlyFlix
做為目標,然後按一下「Add Package」。
設定 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()
}
...
}
- 在「Destination」下拉式選單中選取 iOS 模擬器。
- 在 Xcode 中按下 CMD+R (或點選「Run」按鈕),即可在模擬器上執行應用程式。
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
類型中填入 id
欄位,並填入 UUID。
插入電影和電影中繼資料的模擬資料
定義好結構定義後,您現在可以預先在資料庫中填入模擬資料進行測試。
- 在 Finder 中,將
finish/FriendlyFlix/dataconnect/moviedata_insert.gql
複製到start/FriendlyFlix/dataconnect
資料夾。 - 在 VS Code 中開啟
dataconnect/moviedata_insert.gql
。 - 確認 Firebase Data Connect 擴充功能中的模擬器是否正在執行。
- 檔案頂端應該會顯示「Run (local)」按鈕。按一下這個按鈕,即可將模擬電影資料插入資料庫。
- 查看 Data Connect Execution 終端機,確認資料是否已成功新增。
資料就緒後,請繼續進行下一個步驟,瞭解如何在 Data Connect 中建立查詢。
5. 擷取及顯示電影
在本節中,您將實作顯示電影清單的功能。
首先,您將瞭解如何建立查詢,從 movies
資料表中擷取所有電影。Firebase Data Connect 會為類型安全的 SDK 產生程式碼,您可以用來執行查詢,並在應用程式的 UI 中顯示擷取的電影。
定義 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
}
}
如要測試新查詢,請按一下「Run (local)」按鈕,對本機資料庫執行查詢。資料庫中的電影清單應顯示在 Data Connect 執行終端的「結果」部分下方。
將 ListMovies 查詢連結至應用程式的主畫面
在 Data Connect Emulator 中測試查詢後,您可以從應用程式中呼叫查詢。
儲存 queries.gql
時,Firebase Data Connect 會在 FriendlyFlixSDK
套件中產生與 ListMovies
查詢相對應的程式碼。
在 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 中,按一下「Run」按鈕,即可在 iOS 模擬器中啟動應用程式。
應用程式啟動後,您會看到類似下圖的畫面:
您可能會發現,應用程式的所有區域 (主打區、熱門電影和觀看清單) 都會顯示相同的清單。這是因為您對所有檢視畫面使用相同的查詢。在後續章節中,您將實作自訂查詢。 |
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
中的程式碼,以便使用這些額外功能。
在 UI 中使用強化查詢
返回 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
}
}
}
最後,更新計算屬性,將此查詢的結果連結至 UI:
extension HomeScreen {
...
private var topMovies: [Movie] {
topMoviesRef.data?.movies.map(Movie.init) ?? []
}
}
體驗實際運作情形
再次執行應用程式,即可在主畫面中看到最近的 3 部電影,以及熱門電影專區中評分最高的 5 部電影:
7. 顯示電影和演員詳細資料
使用者現在可以瀏覽電影。輕觸電影資訊卡後,系統會顯示一些電影詳細資料,但你可能會發現這些詳細資料缺乏某些... 詳細資訊!
這是因為我們只擷取每部電影的必要詳細資料,以便顯示電影主打區和熱門電影區:電影名稱、簡短說明和圖片網址。
在電影詳細資料頁面上,我們會顯示更多關於電影的資訊。在本節中,您將強化應用程式,讓應用程式能在詳細資料頁面上顯示電影演員和任何評論。
為此,您需要執行以下幾項操作:
- 強化結構定義,支援電影演員和評論
- 編寫 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 擴充功能中的模擬器是否正在執行。
- 檔案頂端應該會顯示「Run (local)」按鈕。按一下這個按鈕,即可將模擬電影資料插入資料庫。
- 查看資料連結執行終端,確認資料是否已成功新增。
資料就緒後,請繼續進行下一個步驟,定義用來擷取電影詳細資料的查詢。
定義 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 中按一下「Run」按鈕,即可在 iOS 模擬器上啟動應用程式。
應用程式啟動後,輕觸電影資訊卡即可顯示電影詳細資料。內容應該會類似這樣:
8. 實作使用者驗證
目前,應用程式會顯示非個人化的電影和演員資訊。在後續步驟中,您將實作可將資料與已登入使用者建立關聯的功能。首先,您可以允許使用者將電影新增至個人待觀看影劇清單。
您必須先建立使用者身分,才能導入監控清單功能。如要啟用這項功能,您必須整合 Firebase 驗證,讓使用者登入應用程式。
你可能已經在主畫面右上方看到使用者顯示圖片按鈕。輕觸這項功能後,系統會顯示畫面,讓使用者使用電子郵件地址和密碼註冊或登入。
使用者成功登入後,應用程式就需要儲存他們的重要詳細資料,主要是他們的專屬使用者 ID 和所選使用者名稱。
啟用 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
註冊在使用者登入時會呼叫的結束函式。
您可以在該函式內部,在資料庫中建立新的使用者帳戶。不過,您必須先建立可在資料庫中建立或更新新使用者的 mutation。
將使用者實體新增至結構定義
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 驗證註冊時,插入新使用者 (或更新同 ID 的現有使用者)。
體驗實際運作情形
如要確認這項功能是否正常運作,請先在 iOS 應用程式中登入:
- 如果您尚未執行此操作,請停止並重新啟動 Firebase Emulator,確保 Firebase 驗證模擬器正在執行。
- 在 Xcode 中按一下「Run」按鈕,即可在 iOS 模擬器上啟動應用程式。
- 按一下畫面右上角的顯示圖片圖示。
- 切換至「註冊」流程,並註冊應用程式。
接著,請查詢資料庫,確認應用程式已為使用者建立新使用者帳戶:
- 在 VS Code 中開啟
dataconnect/schema/schema.gql
,然後按一下User
實體上的「Read data」 - 這會建立名為
User_read.gql
的新查詢檔案 - 按一下「Run local」,即可查看使用者表格中的所有使用者
- 在「資料連結執行」窗格中,您現在應該會看到剛註冊
的使用者帳戶
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!
}
定義新增和移除收藏項目的 mutation
應用程式必須先知道使用者喜愛的電影,才能顯示相關內容。如要達成這項目標,您必須先新增兩個變異,分別將電影標示為使用者的收藏內容,或再次將電影從收藏內容中移除。
- 在 VS Code 中,在
dataconnect/connector/mutations.gql
中開啟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 })
}
將 mutation 連結至應用程式的 UI
使用者只要在電影的詳細資料畫面中按一下愛心圖示,即可將電影標示為收藏。
如要將剛剛建立的變異數連結至應用程式的 UI,請在 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)
}
}
}
}
這會更新資料庫中目前電影的收藏狀態。最後一個缺少的步驟是確保 UI 狀態能相應反映。
定義查詢,用於判斷電影是否標示為收藏影片
- 在 VS Code 中,開啟
dataconnect/connector
中的queries.gql
。 - 新增以下查詢,檢查電影是否已標示為收藏:
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 中開啟
dataconnect/connector/queries.gql
中的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 Emulator 是否正在執行
- 請確認您已為電影和電影詳細資料新增模擬資料
- 確認您已以使用者身分註冊
- 在 Xcode 中按一下「Run」按鈕,即可在 iOS 模擬器上啟動應用程式。
- 應用程式啟動後,輕觸電影資訊卡即可顯示電影詳細資料。
- 輕觸愛心圖示,即可將電影加入收藏。心形圖示應變成實心。
- 重複執行這項操作,直到有幾部電影都完成為止。
- 前往「媒體庫」分頁。畫面上應該會列出你將其標示為收藏的所有電影。
10. 恭喜!
恭喜,您已成功將 Firebase Data Connect 新增至 iOS 應用程式!您現在已瞭解設定 Data Connect、建立查詢和變異式,以及處理使用者驗證所需的重要步驟。
選用:部署至正式環境
目前這個應用程式只使用 Firebase 模擬器。如要瞭解如何將此應用程式部署至實際的 Firebase 專案,請繼續進行下一個步驟。
11. (選用) 部署應用程式
到目前為止,這個應用程式完全在本機執行,所有資料都包含在 Firebase 模擬器套件中。在本節中,您將瞭解如何設定 Firebase 專案,讓這個應用程式能在正式環境中運作。
啟用 Firebase 驗證
- 在 Firebase 控制台中,前往「驗證」專區,然後按一下「開始使用」。
- 前往「Sign-in method」分頁。
- 在原生供應商部分選取「電子郵件/密碼」選項,
- 啟用電子郵件/密碼供應器,然後按一下「儲存」。
啟用 Firebase Data Connect
重要事項:如果這是您第一次在專案中部署結構定義,這個程序會建立 Cloud SQL PostgreSQL 執行個體,這可能需要 15 分鐘的時間。您必須先準備好 Cloud SQL 執行個體並整合 Firebase Data Connect,才能進行部署。
1. 在 Firebase Data Connect VS Code 擴充功能 UI 中,按一下「部署至正式版」。2. 您可能需要檢查結構定義變更,並核准可能會造成破壞性的修改。系統會提示您:- 使用 firebase dataconnect:sql:diff
查看結構定義變更 - 滿意變更後,使用 firebase dataconnect:sql:migrate
啟動的流程套用變更
您的 PostgreSQL 適用 Cloud SQL 執行個體會更新為最終部署的結構定義和資料。您可以在 Firebase 主控台中監控狀態。
您現在可以按一下 Firebase Data Connect 面板中的「Run (Production)」(執行 (實際工作環境)」,就像使用本機模擬器一樣,將資料新增至實際工作環境。
再次執行 iOS 應用程式前,請確認應用程式已連線至專案的正式版例項:
- 依序開啟「Product」>「Scheme」>「Edit Scheme...」選單。
- 在「Run」專區中,取消勾選
-useEmulator YES
啟動引數。