1. Tổng quan
Lớp học lập trình này hướng dẫn bạn thực hiện quy trình tích hợp Firebase Data Connect với cơ sở dữ liệu Cloud SQL để tạo ứng dụng đánh giá phim cho iOS bằng SwiftUI
Bạn sẽ tìm hiểu cách kết nối ứng dụng iOS với cơ sở dữ liệu Cloud SQL bằng Firebase Data Connect, cho phép đồng bộ hoá dữ liệu liền mạch cho bài đánh giá phim.
Khi kết thúc lớp học lập trình này, bạn sẽ có một ứng dụng iOS có chức năng cho phép người dùng duyệt xem phim và đánh dấu phim là phim yêu thích. Tất cả đều được hỗ trợ bởi cơ sở dữ liệu Cloud SQL bằng cách sử dụng tính năng Firebase Data Connect.
Kiến thức bạn sẽ học được
Lớp học lập trình này sẽ hướng dẫn bạn cách:
- Thiết lập Firebase Data Connect bằng bộ Trình mô phỏng Firebase để có thời gian hoàn thành nhanh chóng.
- Thiết kế giản đồ cơ sở dữ liệu bằng Data Connect và GraphQL.
- Tạo SDK Swift an toàn về kiểu từ giản đồ cơ sở dữ liệu và thêm SDK đó vào ứng dụng Swift.
- Triển khai tính năng xác thực người dùng và tích hợp tính năng này với Firebase Data Connect để bảo mật dữ liệu của người dùng.
- Truy xuất, cập nhật, xoá và quản lý dữ liệu trong Cloud SQL bằng truy vấn và đột biến do GraphQL cung cấp.
- (Không bắt buộc) Triển khai dịch vụ Data Connect cho môi trường phát hành chính thức.
Điều kiện tiên quyết
- Phiên bản Xcode mới nhất
- Mã mẫu của lớp học lập trình. Bạn sẽ tải mã mẫu xuống trong một trong những bước đầu tiên của lớp học lập trình này.
2. Thiết lập dự án mẫu
Tạo dự án Firebase
- Đăng nhập vào bảng điều khiển của Firebase bằng Tài khoản Google của bạn.
- Trong bảng điều khiển của Firebase, hãy nhấp vào Tạo dự án Firebase.
- Nhập tên cho dự án Firebase của bạn (ví dụ: "Friendly Flix") rồi nhấp vào Tiếp tục.
- Bạn có thể được yêu cầu bật tính năng hỗ trợ AI cho dự án Firebase. Đối với mục đích của lớp học lập trình này, lựa chọn của bạn không quan trọng.
- Bạn có thể được yêu cầu bật Google Analytics. Đối với mục đích của lớp học lập trình này, lựa chọn của bạn không quan trọng.
- Sau khoảng một phút, dự án Firebase của bạn sẽ sẵn sàng. Nhấp vào Tiếp tục.
Tải mã xuống
Chạy lệnh sau để nhân bản mã mẫu cho lớp học lập trình này. Thao tác này sẽ tạo một thư mục có tên codelab-dataconnect-ios
trên máy của bạn:
git clone https://github.com/peterfriese/codelab-dataconnect-ios`
Nếu không có git trên máy, bạn cũng có thể tải mã xuống trực tiếp từ GitHub.
Thêm cấu hình Firebase
SDK Firebase sử dụng tệp cấu hình để kết nối với dự án Firebase của bạn. Trên các nền tảng của Apple, tệp này có tên là GoogleServices-Info.plist
. Ở bước này, bạn sẽ tải tệp cấu hình xuống và thêm tệp đó vào dự án Xcode.
- Trong bảng điều khiển của Firebase, hãy chọn Tổng quan về dự án trong thanh điều hướng bên trái.
- Nhấp vào nút iOS+ để chọn nền tảng. Khi được nhắc nhập mã nhận dạng gói Apple, hãy sử dụng
com.google.firebase.samples.FriendlyFlix
- Nhấp vào Đăng ký ứng dụng rồi làm theo hướng dẫn để tải tệp
GoogleServices-Info.plist
xuống. - Di chuyển tệp đã tải xuống vào thư mục
start/FriendlyFlix/app/FriendlyFlix/FriendlyFlix/
của mã bạn vừa tải xuống, thay thế tệpGoogleServices-Info.plist
hiện có. - Sau đó, nhấp vào Tiếp theo vài lần để hoàn tất dự án thiết lập trong bảng điều khiển Firebase (bạn không cần thêm SDK vào ứng dụng vì việc này đã được thực hiện cho bạn trong dự án khởi động).
- Cuối cùng, hãy nhấp vào Tiếp tục đến bảng điều khiển để hoàn tất quy trình thiết lập.
3. Thiết lập Data Connect
Lắp đặt
Cài đặt tự động
Chạy lệnh sau trong thư mục codelab-dataconnect-ios/FriendlyFlix
:
curl -sL https://firebase.tools/dataconnect | bash
Tập lệnh này sẽ cố gắng thiết lập môi trường phát triển cho bạn và chạy một IDE dựa trên trình duyệt. IDE này cung cấp các công cụ, bao gồm cả tiện ích VS Code được đóng gói sẵn, để giúp bạn quản lý giản đồ và xác định các truy vấn và đột biến sẽ được sử dụng trong ứng dụng, cũng như tạo các SDK có kiểu mạnh.
Sau khi chạy tập lệnh, VS Code sẽ tự động mở ra.
Sau khi thực hiện một lần, bạn có thể bắt đầu VS Code bằng cách chạy VS Code trong thư mục cục bộ:
code .
Cài đặt theo cách thủ công
- Cài đặt Visual Studio Code
- Cài đặt Node.js
- Trong VS Code, hãy mở thư mục
codelab-dataconnect-ios/FriendlyFlix
. - Cài đặt tiện ích Firebase Data Connect từ Visual Studio Code Marketplace.
Khởi chạy Data Connect trong dự án
Trong bảng điều khiển bên trái, hãy nhấp vào biểu tượng Firebase để mở giao diện người dùng của tiện ích Data Connect VS Code
- Nhấp vào nút Đăng nhập bằng Google. Một cửa sổ trình duyệt sẽ mở ra; hãy làm theo hướng dẫn để đăng nhập vào tiện ích bằng Tài khoản Google của bạn.
- Nhấp vào nút Kết nối dự án Firebase rồi chọn dự án mà bạn đã tạo trước đó trong bảng điều khiển.
- Nhấp vào nút Run firebase init (Chạy firebase init) rồi làm theo các bước trong thiết bị đầu cuối tích hợp.
Định cấu hình quá trình tạo SDK
Sau khi bạn nhấp vào nút Run firebase init (Chạy firebase init), tiện ích Firebase Data Connect sẽ khởi chạy thư mục dataconnect
cho bạn.
Trong VS Code, hãy mở tệp dataconnect/connector/connector.yaml
và bạn sẽ thấy cấu hình mặc định.
Vui lòng cập nhật cấu hình và sử dụng các chế độ cài đặt sau để đảm bảo mã được tạo hoạt động với lớp học lập trình này. Cụ thể, hãy đảm bảo rằng connectorId
được đặt thành friendly-flix
và gói Swift được đặt thành FriendlyFlixSDK
.
connectorId: "friendly-flix"
generate:
swiftSdk:
outputDir: "../../app"
package: "FriendlyFlixSDK"
observablePublisher: observableMacro
Dưới đây là ý nghĩa của các chế độ cài đặt này:
connectorId
– tên duy nhất cho trình kết nối này.outputDir
– đường dẫn nơi lưu trữ SDK Data Connect đã tạo. Đường dẫn này tương ứng với thư mục chứa tệpconnector.yaml
.package
– tên gói sẽ được dùng cho gói Swift đã tạo.
Sau khi bạn lưu tệp này, Firebase Data Connect sẽ tạo một gói Swift có tên FriendlyFlixSDK
cho bạn và đặt gói đó bên cạnh thư mục dự án FriendlyFlix
.
Khởi động trình mô phỏng Firebase
Trong VS Code, hãy chuyển sang chế độ xem Firebase, sau đó nhấp vào nút Start emulators (Bắt đầu trình mô phỏng).
Thao tác này sẽ khởi động Trình mô phỏng Firebase trong dòng lệnh tích hợp. Kết quả sẽ có dạng như sau:
npx -y firebase-tools@latest emulators:start --project <your-project-id>
Thêm gói đã tạo vào ứng dụng Swift
- Mở
FriendlyFlix/app/FriendlyFlix/FriendlyFlix.xcodeproj
trong Xcode - Chọn File > Add Package Dependencies... (Tệp > Thêm phần phụ thuộc gói...).
- Nhấp vào Add Local... (Thêm cục bộ), sau đó thêm gói
FriendlyFlixSDK
từ thư mụcFriendlyFlix/app
- Chờ Xcode phân giải các phần phụ thuộc của gói.
- Trong hộp thoại Choose Package Products for FriendlyFlixSDK (Chọn sản phẩm gói cho FriendlyFlixSDK), hãy chọn
FriendlyFlix
làm mục tiêu rồi nhấp vào Add Package (Thêm gói).
Định cấu hình ứng dụng iOS để sử dụng trình mô phỏng cục bộ
- Mở
FriendlyFlixApp.swift
. (Bạn có thể nhấn tổ hợp phím CMD + Shift + O để mở hộp thoại Quick Open (Mở nhanh), sau đó nhập "FriendlyFlixApp" để tìm nhanh tệp) - Nhập Firebase, Firebase Auth, Firebase Data Connect và SDK đã tạo cho giản đồ
- Trong trình khởi tạo, hãy định cấu hình Firebase.
- Đảm bảo DataConnect và Firebase Auth sử dụng trình mô phỏng cục bộ.
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()
}
...
}
- Chọn một Trình mô phỏng iOS trong trình đơn thả xuống Đích đến.
- Nhấn tổ hợp phím CMD+R (hoặc nhấp vào nút Run (Chạy)) trong Xcode để chạy ứng dụng trên Trình mô phỏng.
4. Xác định giản đồ và điền sẵn cơ sở dữ liệu
Trong phần này, bạn sẽ xác định cấu trúc và mối quan hệ giữa các thực thể chính trong ứng dụng phim trong một giản đồ. Các thực thể như Movie
, MovieMetaData
và các thực thể khác được liên kết với các bảng cơ sở dữ liệu, với các mối quan hệ được thiết lập bằng cách sử dụng Firebase Data Connect và các lệnh của giản đồ GraphQL.
Các thực thể và mối quan hệ cốt lõi
Mô hình dữ liệu cho ứng dụng theo dõi phim này bao gồm một số thực thể mà bạn sẽ tạo trong quá trình tham gia lớp học lập trình này. Trước tiên, bạn sẽ tạo các thực thể cốt lõi và khi triển khai ngày càng nhiều tính năng, bạn sẽ thêm các thực thể cần thiết cho các tính năng đó.
Ở bước này, bạn sẽ tạo các loại Movie
và MovieMetadata
.
Phim
Loại Movie
xác định cấu trúc chính cho một thực thể phim, bao gồm các trường như title
, genre
, releaseYear
và rating
.
Trong VS Code, hãy thêm định nghĩa loại Movie
vào 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
Loại MovieMetadata
thiết lập mối quan hệ một với một với loại Movie
. Dữ liệu này bao gồm các dữ liệu bổ sung như đạo diễn của phim.
Thêm định nghĩa bảng MovieMetadata
vào tệp dataconnect/schema/schema.gql
:
type MovieMetadata @table {
movie: Movie! @ref
director: String
}
Các trường được tạo tự động và giá trị mặc định
Giản đồ sử dụng các biểu thức như @default(expr: "uuidV4()")
để tự động tạo mã nhận dạng và dấu thời gian duy nhất. Ví dụ: trường id
trong loại Movie
sẽ tự động được điền bằng UUID khi một bản ghi mới được tạo.
Chèn dữ liệu mô phỏng cho phim và siêu dữ liệu phim
Khi đã xác định giản đồ, bạn có thể điền sẵn cơ sở dữ liệu bằng dữ liệu mô phỏng để kiểm thử.
- Trong Finder, hãy sao chép
finish/FriendlyFlix/dataconnect/moviedata_insert.gql
vào thư mụcstart/FriendlyFlix/dataconnect
. - Trong VS Code, hãy mở
dataconnect/moviedata_insert.gql
. - Đảm bảo trình mô phỏng trong tiện ích Firebase Data Connect đang chạy.
- Bạn sẽ thấy nút Run (local) (Chạy (trên máy)) ở đầu tệp. Nhấp vào nút này để chèn dữ liệu phim mô phỏng vào cơ sở dữ liệu.
- Kiểm tra thiết bị đầu cuối Data Connect Execution (Thực thi kết nối dữ liệu) để xác nhận rằng dữ liệu đã được thêm thành công.
Khi đã có dữ liệu, hãy chuyển sang bước tiếp theo để tìm hiểu cách tạo truy vấn trong Data Connect.
5. Truy xuất và hiển thị phim
Trong phần này, bạn sẽ triển khai một tính năng để hiển thị danh sách phim.
Trước tiên, bạn sẽ tìm hiểu cách tạo truy vấn truy xuất tất cả phim trong bảng movies
. Firebase Data Connect tạo mã cho một SDK an toàn về loại mà bạn có thể sử dụng để thực thi truy vấn và hiển thị các bộ phim được truy xuất trong giao diện người dùng của ứng dụng.
Xác định truy vấn ListMovies
Các truy vấn trong Firebase Data Connect được viết bằng GraphQL, cho phép bạn chỉ định các trường cần tìm nạp. Trong FriendlyFlix, các màn hình hiển thị phim cần có các trường sau: title
, description
, releaseYear
, rating
và imageUrl
. Ngoài ra, vì đây là ứng dụng SwiftUI nên bạn sẽ cần id
để hỗ trợ nhận dạng khung hiển thị SwiftUI.
Trong VS Code, hãy mở tệp dataconnect/connector/queries.gql
rồi thêm truy vấn ListMovies
:
query ListMovies @auth(level: PUBLIC) {
movies {
id
title
imageUrl
releaseYear
genre
rating
tags
description
}
}
Để kiểm thử truy vấn mới, hãy nhấp vào nút Run (local) (Chạy (tại máy)) để thực thi truy vấn trên cơ sở dữ liệu cục bộ. Danh sách phim trong cơ sở dữ liệu sẽ xuất hiện trong mục Kết quả của thiết bị đầu cuối Thực thi Data Connect.
Kết nối truy vấn ListMovies với màn hình chính của ứng dụng
Giờ đây, khi đã kiểm thử truy vấn trong Trình mô phỏng Data Connect, bạn có thể gọi truy vấn từ bên trong ứng dụng.
Khi bạn lưu queries.gql
, Firebase Data Connect sẽ tạo mã tương ứng với truy vấn ListMovies
trong gói FriendlyFlixSDK
.
Trong Xcode, hãy mở Movie+DataConnect.swift
rồi thêm mã sau để liên kết từ ListMoviesQuery.Data.Movie
đến 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
}
}
Mở tệp HomeScreen.swift
và cập nhật tệp đó bằng đoạn mã sau.
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) ?? []
}
...
}
Truy vấn |
Chạy ứng dụng
Trong Xcode, hãy nhấp vào nút Run (Chạy) để chạy ứng dụng trong Trình mô phỏng iOS.
Sau khi ứng dụng khởi chạy, bạn sẽ thấy một màn hình như sau:
Bạn có thể nhận thấy rằng tất cả các khu vực của ứng dụng (phần chính, phim hàng đầu và danh sách xem) đều hiển thị cùng một danh sách. Điều này là do bạn đang sử dụng cùng một truy vấn cho tất cả các chế độ xem đó. Trong các phần tiếp theo, bạn sẽ triển khai truy vấn tuỳ chỉnh. |
6. Hiển thị hình ảnh chính và các bộ phim hàng đầu
Trong bước này, bạn sẽ tập trung cập nhật cách hiển thị phim trong phần chủ đề – đó là băng chuyền nổi bật ở đầu màn hình chính – cũng như trong phần phim hàng đầu ở bên dưới.
Hiện tại, truy vấn ListMovies truy xuất tất cả phim. Để tối ưu hoá chế độ hiển thị cho các phần này, bạn sẽ giới hạn số lượng phim mà mỗi truy vấn trả về. Cách triển khai truy vấn ListMovies
hiện tại chưa hỗ trợ tích hợp để giới hạn kết quả – bạn sẽ thêm tính năng hỗ trợ giới hạn và sắp xếp trong phần này.
Cải thiện truy vấn ListMovies
Mở queries.gql
và cập nhật ListMovies
như sau để thêm tính năng hỗ trợ sắp xếp và giới hạn:
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
}
}
Điều này sẽ cho phép bạn giới hạn số lượng phim mà truy vấn trả về, đồng thời sắp xếp tập hợp kết quả theo cả điểm xếp hạng và năm phát hành.
Sau khi bạn lưu tệp này, Firebase Data Connect sẽ tự động tạo lại mã trong FriendlyFlixSDK
. Trong bước tiếp theo, bạn có thể cập nhật mã trong HomeScreen.swift
để sử dụng các tính năng bổ sung này.
Sử dụng truy vấn nâng cao trong giao diện người dùng
Quay lại Xcode để thực hiện các thay đổi cần thiết đối với HomeScreen.swift
.
Trước tiên, hãy cập nhật heroMoviesRef
để tìm nạp 3 bộ phim mới phát hành gần đây nhất:
struct HomeScreen {
...
init() {
heroMoviesRef = connector.listMoviesQuery
.ref { optionalVars in
optionalVars.limit = 3
optionalVars.orderByReleaseYear = .DESC
}
}
}
Tiếp theo, hãy thiết lập một tham chiếu truy vấn khác cho các bộ phim hàng đầu và đặt bộ lọc thành 5 bộ phim được xếp hạng cao nhất:
struct HomeScreen {
...
let topMoviesRef: QueryRefObservation<ListMoviesQuery.Data, ListMoviesQuery.Variables>
init() {
heroMoviesRef = ...
topMoviesRef = connector.listMoviesQuery
.ref { optionalVars in
optionalVars.limit = 5
optionalVars.orderByRating = .DESC
}
}
}
Cuối cùng, hãy cập nhật thuộc tính được tính toán để kết nối kết quả của truy vấn này với giao diện người dùng:
extension HomeScreen {
...
private var topMovies: [Movie] {
topMoviesRef.data?.movies.map(Movie.init) ?? []
}
}
Xem cách thức hoạt động
Chạy lại ứng dụng để xem 3 bộ phim gần đây nhất trong phần anh hùng và 5 bộ phim được đánh giá cao nhất trong phần phim hàng đầu:
7. Hiển thị thông tin chi tiết về phim và diễn viên
Giờ đây, người dùng có thể duyệt xem phim. Khi nhấn vào một thẻ phim, người dùng sẽ thấy một số thông tin chi tiết về phim, nhưng có thể bạn đã nhận thấy rằng thông tin chi tiết này thiếu một số thông tin nhất định!
Lý do là chúng ta chỉ tìm nạp đủ thông tin chi tiết về từng bộ phim để hiển thị phần nhân vật chính trong phim và phần phim ăn khách nhất: tên phim, nội dung mô tả ngắn và URL hình ảnh.
Trên trang chi tiết của phim, chúng ta sẽ muốn hiển thị thêm thông tin về phim. Trong phần này, bạn sẽ cải thiện ứng dụng để ứng dụng có thể hiển thị diễn viên của phim và mọi bài đánh giá trên trang chi tiết.
Để làm việc này, bạn cần thực hiện một số việc:
- Cải thiện giản đồ để hỗ trợ diễn viên và bài đánh giá phim
- Viết truy vấn Firebase Data Connect để tìm nạp thông tin chi tiết về một bộ phim cụ thể
- Hiển thị kết quả trên màn hình thông tin chi tiết về phim
Cải thiện giản đồ
Trong VS Code, hãy mở dataconnect/schema/schema.gql
và thêm định nghĩa giản đồ cho Actor
và 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"
}
Thêm dữ liệu mô phỏng cho các diễn viên
Sau khi cập nhật giản đồ, bạn có thể điền thêm dữ liệu mô phỏng vào cơ sở dữ liệu để kiểm thử.
- Trong Finder, hãy sao chép
finish/FriendlyFlix/dataconnect/moviededetails_insert.gql
vào thư mụcstart/FriendlyFlix/dataconnect
. - Trong VS Code, hãy mở
dataconnect/moviededetails_insert.gql
. - Đảm bảo trình mô phỏng trong tiện ích Firebase Data Connect đang chạy.
- Bạn sẽ thấy nút Run (local) (Chạy (trên máy)) ở đầu tệp. Nhấp vào nút này để chèn dữ liệu phim mô phỏng vào cơ sở dữ liệu.
- Kiểm tra thiết bị đầu cuối Data Connect Execution (Thực thi kết nối dữ liệu) để xác nhận rằng dữ liệu đã được thêm thành công.
Khi đã có dữ liệu, hãy chuyển sang bước tiếp theo để xác định truy vấn nhằm tìm nạp thông tin chi tiết về phim.
Xác định truy vấn GetMovieById
Trong VS Code, hãy mở tệp dataconnect/connector/queries.gql
rồi thêm truy vấn 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
}
}
}
Kết nối truy vấn GetMovieById với MovieDetailsView
Trong Xcode, hãy mở tệp MovieDetailsView.swift
và cập nhật thuộc tính được tính toán movieDetails
sao cho khớp với mã sau:
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
}
}
Chạy ứng dụng
Trong Xcode, hãy nhấp vào nút Run (Chạy) để chạy ứng dụng trên Trình mô phỏng iOS.
Sau khi ứng dụng khởi chạy, hãy nhấn vào một thẻ phim để hiển thị thông tin chi tiết về phim. Mã sẽ có dạng như sau:
8. Triển khai quy trình xác thực người dùng
Hiện tại, ứng dụng này hiển thị thông tin về diễn viên và phim không được cá nhân hoá. Trong các bước sau, bạn sẽ triển khai các tính năng liên kết dữ liệu với người dùng đã đăng nhập. Bạn sẽ bắt đầu bằng cách cho phép người dùng thêm phim vào danh sách xem cá nhân của họ.
Trước khi có thể triển khai tính năng danh sách xem, trước tiên, bạn cần thiết lập danh tính người dùng. Để bật tính năng này, bạn sẽ tích hợp tính năng Xác thực Firebase, cho phép người dùng đăng nhập vào ứng dụng.
Có thể bạn đã thấy nút hình đại diện người dùng ở góc trên cùng bên phải của màn hình chính. Khi nhấn vào nút này, bạn sẽ được chuyển đến màn hình mà người dùng có thể đăng ký hoặc đăng nhập bằng email và mật khẩu của họ.
Sau khi người dùng đăng nhập thành công, ứng dụng của bạn sẽ cần lưu trữ thông tin chi tiết thiết yếu của họ, chủ yếu là mã nhận dạng người dùng duy nhất và tên người dùng mà họ đã chọn.
Bật tính năng Xác thực Firebase
Trong bảng điều khiển của Firebase cho dự án, hãy chuyển đến mục Xác thực và bật tính năng Xác thực bằng Firebase. Sau đó, hãy bật trình cung cấp xác thực Email/Mật khẩu.
Trong thư mục dự án cục bộ, hãy tìm firebase.json
và cập nhật như sau để bật trình mô phỏng Xác thực Firebase.
{
"emulators": {
"dataconnect": {
},
"auth": {
}
},
"dataconnect": {
"source": "dataconnect"
}
}
Sau đó, bạn cần dừng và khởi động lại Trình mô phỏng Firebase để thay đổi có hiệu lực.
Triển khai trình xử lý xác thực
Trong phần sau, bạn sẽ triển khai logic kết nối quy trình xác thực người dùng với cơ sở dữ liệu. Điều này liên quan đến việc tạo một trình xử lý xác thực để theo dõi các lượt đăng nhập thành công.
Sau khi người dùng được xác thực, trình xử lý này sẽ tự động kích hoạt việc tạo tài khoản tương ứng của họ trong cơ sở dữ liệu của bạn.
Trong Xcode, hãy mở tệp AuthenticationService.swift
rồi thêm mã sau:
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
}
}
Đây là trình xử lý xác thực chung cho phép bạn sử dụng onSignUp
để đăng ký một hàm đóng sẽ được gọi khi người dùng đăng nhập.
Bên trong hàm đóng đó, bạn có thể tạo một tài khoản người dùng mới trong cơ sở dữ liệu. Tuy nhiên, trước khi có thể làm việc này, bạn cần tạo một đột biến cho phép bạn tạo hoặc cập nhật người dùng mới trong cơ sở dữ liệu.
Thêm thực thể Người dùng vào giản đồ
Loại User
xác định một thực thể người dùng. Người dùng có thể tương tác với phim bằng cách viết bài đánh giá hoặc thêm phim vào danh sách yêu thích.
Trong VS Code, hãy mở tệp dataconnect/schema/schema.gql
rồi thêm định nghĩa bảng User
sau:
## 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)")
}
Xác định một đột biến để chèn hoặc cập nhật người dùng
Trong VS Code, hãy mở tệp dataconnect/connector/mutations.gql
và thêm đột biến UpsertUser
:
mutation UpsertUser($username: String!) @auth(level: USER) {
user_upsert(
data: {
id_expr: "auth.uid"
username: $username
}
)
}
Tạo người dùng mới sau khi đăng nhập thành công
Trong Xcode, hãy mở FriendlyFlixApp.swift
rồi thêm mã sau vào trình khởi tạo:
@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 {
...
}
}
Mã này sử dụng Firebase Data Connect upsertUserMutation
được tạo để bạn chèn người dùng mới (hoặc cập nhật người dùng hiện tại có cùng mã nhận dạng) bất cứ khi nào người dùng đăng ký thành công bằng tính năng Xác thực Firebase.
Xem cách thức hoạt động
Để xác minh tính năng này có hoạt động hay không, trước tiên, hãy đăng ký trong ứng dụng iOS:
- Nếu chưa, hãy dừng và khởi động lại Trình mô phỏng Firebase để đảm bảo Trình mô phỏng xác thực Firebase đang chạy.
- Trong Xcode, hãy nhấp vào nút Run (Chạy) để chạy ứng dụng trên Trình mô phỏng iOS.
- Nhấp vào biểu tượng hình đại diện ở góc trên cùng bên phải màn hình.
- Chuyển sang quy trình Đăng ký và đăng ký ứng dụng.
Sau đó, hãy truy vấn cơ sở dữ liệu để xác minh rằng ứng dụng đã tạo tài khoản người dùng mới cho người dùng:
- Trong VS Code, hãy mở
dataconnect/schema/schema.gql
rồi nhấp vào Read data (Đọc dữ liệu) trên thực thểUser
- Thao tác này sẽ tạo một tệp truy vấn mới có tên là
User_read.gql
- Nhấp vào Run local (Chạy cục bộ) để xem tất cả người dùng trong bảng users
- Trong ngăn Data Connect Execution (Thực thi Data Connect), bạn sẽ thấy một tài khoản cho người dùng mà bạn vừa đăng ký bằng
9. Quản lý phim yêu thích
Trong phần này của lớp học lập trình, bạn sẽ triển khai các hoạt động tương tác của người dùng trong ứng dụng đánh giá phim, cụ thể là cho phép người dùng quản lý các bộ phim mà họ yêu thích. Những bộ phim được đánh dấu là yêu thích sẽ xuất hiện trong phần danh sách xem của ứng dụng.
Cải thiện giản đồ để hỗ trợ mục yêu thích
Loại FavoriteMovie
là một bảng nối xử lý mối quan hệ nhiều với nhiều giữa người dùng và phim mà họ yêu thích. Mỗi bảng liên kết một User
với một Movie
.
Sao chép và dán đoạn mã vào tệp 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!
}
Xác định các đột biến để thêm và xoá mục yêu thích
Trước khi ứng dụng có thể hiển thị các bộ phim mà người dùng yêu thích, người dùng cần cho biết những bộ phim nào họ yêu thích. Để làm được điều này, trước tiên, bạn cần thêm hai đột biến để đánh dấu một bộ phim là một trong những bộ phim yêu thích của người dùng hoặc xoá bộ phim đó khỏi danh sách yêu thích của họ.
- Trong VS Code, hãy mở
mutations.gql
trongdataconnect/connector/mutations.gql
- Thêm các đột biến sau để xử lý việc thêm phim vào danh sách yêu thích:
## 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 })
}
Kết nối các đột biến với giao diện người dùng của ứng dụng
Người dùng có thể đánh dấu một bộ phim là yêu thích bằng cách nhấp vào biểu tượng trái tim trên màn hình chi tiết của bộ phim.
Để kết nối các đột biến bạn vừa tạo với giao diện người dùng của ứng dụng, hãy thực hiện các thay đổi sau trong MovieCardView
:
- Nhập
FriendlyFlixSDK
và thiết lập trình kết nối
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
...
}
- Triển khai phương thức
toggleFavourite
. Phương thức này sẽ được gọi mỗi khi người dùng nhấn vào biểu tượng trái tim trongMovieCardView
:
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)
}
}
}
}
Thao tác này sẽ cập nhật trạng thái yêu thích của phim hiện tại trong cơ sở dữ liệu. Còn một bước cuối cùng cần thực hiện là đảm bảo trạng thái giao diện người dùng được phản ánh tương ứng.
Xác định truy vấn để tìm hiểu xem một bộ phim có được đánh dấu là yêu thích hay không
- Trong VS Code, hãy mở
queries.gql
trongdataconnect/connector
. - Thêm truy vấn sau để kiểm tra xem một bộ phim có được đánh dấu là yêu thích hay không:
query GetIfFavoritedMovie($movieId: UUID!) @auth(level: USER) {
favorite_movie(key: { userId_expr: "auth.uid", movieId: $movieId }) {
movieId
}
}
- Trong Xcode, hãy tạo bản sao tham chiếu đến truy vấn
GetIfFavoritedMovie
và triển khai thuộc tính được tính toán để xác định xem bộ phim hiển thị trênMovieCardView
này có được đánh dấu là yêu thích cho người dùng hiện tại hay không.
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
}
...
}
- Cập nhật mã trong
toggleFavourite
để thực thi truy vấn bất cứ khi nào người dùng nhấn vào nút. Điều này giúp đảm bảo rằng thuộc tính được tính toánisFavourite
luôn trả về giá trị chính xác.
private func toggleFavourite() {
Task {
if isFavourite {
...
}
let _ = try await isFavouriteRef.execute()
}
}
Tìm nạp phim yêu thích
Bước cuối cùng của tính năng này là bạn sẽ triển khai tính năng tìm nạp phim yêu thích của người dùng để họ có thể xem các phim đó trong danh sách xem.
- Trong VS Code, hãy mở
queries.gql
trongdataconnect/connector/queries.gql
rồi dán truy vấn sau:
## 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
}
}
}
}
Danh sách phim yêu thích của người dùng sẽ hiển thị trên LibraryScreen
. Màn hình này chỉ hiển thị dữ liệu nếu người dùng đã đăng nhập, vì vậy, trước tiên, bạn sẽ kết nối trạng thái xác thực của màn hình với AuthenticationService
của ứng dụng.
- Thêm mã để liên kết từ
FavoriteMovieFavoriteMovies
đếnMovie
đếnMovie+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
}
}
- Trong Xcode, hãy mở
LibraryScreen
, sau đó cập nhậtisSignedIn
như sau:
struct LibraryScreen: View {
...
private var isSignedIn: Bool {
authenticationService.user != nil
}
}
- Sau đó, hãy nhập Firebase Data Connect và FriendlyFlixSDK, đồng thời tham chiếu đến truy vấn
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) ?? []
}
...
}
- Đảm bảo truy vấn
watchListRef
được thực thi khi thành phần hiển thị xuất hiện:
extension LibraryScreen: View {
var body: some View {
...
MovieListSection(namespace: namespace, title: "Watch List", movies: watchList)
.onAppear {
Task {
try await watchListRef.execute()
}
...
Xem cách thức hoạt động
Giờ đây, bạn có thể chạy ứng dụng và dùng thử tính năng yêu thích mà bạn vừa triển khai. Một vài điều cần lưu ý:
- Đảm bảo Trình mô phỏng Firebase đang chạy
- Đảm bảo bạn đã thêm dữ liệu mô phỏng cho các bộ phim và thông tin chi tiết về phim
- Đảm bảo bạn đã đăng ký làm người dùng
- Trong Xcode, hãy nhấp vào nút Run (Chạy) để chạy ứng dụng trên Trình mô phỏng iOS.
- Sau khi ứng dụng khởi chạy, hãy nhấn vào một thẻ phim để hiển thị thông tin chi tiết về phim.
- Nhấn vào biểu tượng trái tim để đánh dấu phim là phim yêu thích. Trái tim sẽ chuyển sang màu đen.
- Lặp lại thao tác này cho một vài bộ phim.
- Chuyển đến thẻ Thư viện. Lúc này, bạn sẽ thấy danh sách tất cả phim mà bạn đã đánh dấu là phim yêu thích.
10. Xin chúc mừng
Xin chúc mừng! Bạn đã thêm thành công Firebase Data Connect vào một ứng dụng iOS! Giờ đây, bạn đã biết các bước chính cần thiết để thiết lập Data Connect, tạo truy vấn và đột biến cũng như xử lý việc xác thực người dùng.
Không bắt buộc: triển khai lên kênh phát hành công khai
Cho đến nay, ứng dụng này chỉ sử dụng Trình mô phỏng Firebase. Nếu bạn muốn tìm hiểu cách triển khai ứng dụng này cho một dự án Firebase thực tế, hãy tiếp tục chuyển sang bước tiếp theo.
11. (Không bắt buộc) Triển khai ứng dụng
Cho đến nay, ứng dụng này hoàn toàn ở chế độ cục bộ, tất cả dữ liệu đều nằm trong Bộ mô phỏng Firebase. Trong phần này, bạn sẽ tìm hiểu cách định cấu hình dự án Firebase để ứng dụng này hoạt động trong môi trường phát hành công khai.
Bật tính năng Xác thực Firebase
- Trong bảng điều khiển Firebase, hãy chuyển đến mục Xác thực rồi nhấp vào Bắt đầu.
- Chuyển đến thẻ Phương thức đăng nhập .
- Chọn Email/Mật khẩu trong phần nhà cung cấp gốc,
- Bật nhà cung cấp Email/Mật khẩu, rồi nhấp vào Lưu.
Bật Firebase Data Connect
Lưu ý quan trọng: Nếu đây là lần đầu tiên bạn triển khai giản đồ trong dự án, thì quá trình này sẽ tạo một phiên bản PostgreSQL Cloud SQL. Quá trình này có thể mất khoảng 15 phút. Bạn sẽ không thể triển khai cho đến khi phiên bản Cloud SQL sẵn sàng và được tích hợp với Firebase Data Connect.
1. Trong giao diện người dùng của tiện ích Firebase Data Connect cho VS Code, hãy nhấp vào Deploy to production (Triển khai lên môi trường phát hành chính thức). 2. Bạn có thể cần xem xét các thay đổi về giản đồ và phê duyệt các nội dung sửa đổi có thể gây hại. Bạn sẽ được nhắc: – Xem xét các thay đổi về giản đồ bằng firebase dataconnect:sql:diff
– Khi bạn hài lòng với các thay đổi, hãy áp dụng các thay đổi đó bằng quy trình do firebase dataconnect:sql:migrate
bắt đầu
Phiên bản Cloud SQL cho PostgreSQL sẽ được cập nhật bằng giản đồ và dữ liệu đã triển khai cuối cùng. Bạn có thể theo dõi trạng thái trong Bảng điều khiển của Firebase.
Bây giờ, bạn có thể nhấp vào Run (Production) (Chạy (Sản xuất)) trong bảng điều khiển Firebase Data Connect (Kết nối dữ liệu Firebase), giống như cách bạn đã làm với trình mô phỏng cục bộ, để thêm dữ liệu vào môi trường sản xuất.
Trước khi chạy lại ứng dụng iOS, hãy đảm bảo ứng dụng đó kết nối với phiên bản chính thức của dự án:
- Mở trình đơn Product > Scheme > Edit Scheme... (Sản phẩm > Lược đồ > Chỉnh sửa lược đồ).
- Trong mục Run (Chạy), hãy bỏ đánh dấu đối số khởi chạy
-useEmulator YES
.