1. Tổng quan
Lớp học lập trình này hướng dẫn bạn quy trình tích hợp Firebase Data Connect với cơ sở dữ liệu Cloud SQL để tạo một ứ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 các 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 hoạt động được, 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 sức mạnh của 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ộ mô phỏng Firebase để có thời gian phản hồi nhanh.
- 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 của bạn và thêm SDK đó vào một ứ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 cách sử dụng các 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 hoạt động sản xuất.
Điều kiện tiên quyết
- Phiên bản mới nhất của Xcode
- 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.
2. Thiết lập dự án mẫu
Tạo một 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.
- Nhấp vào nút này để tạo một dự án mới, rồi nhập tên dự án (ví dụ:
Friendly Flix
).
- Nhấp vào Tiếp tục.
- Nếu được nhắc, hãy xem xét và chấp nhận các điều khoản của Firebase, rồi nhấp vào Tiếp tục.
- (Không bắt buộc) Bật tính năng hỗ trợ của AI trong bảng điều khiển của Firebase (còn gọi là "Gemini trong Firebase").
- Đối với lớp học lập trình này, bạn không cần Google Analytics, vì vậy hãy tắt lựa chọn Google Analytics.
- Nhấp vào Tạo dự án, đợi dự án được cấp phép rồi nhấp vào Tiếp tục.
Tải mã xuống
Chạy lệnh sau để sao chép 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 là codelab-dataconnect-ios
trên máy của bạn:
git clone https://github.com/FirebaseExtended/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
Firebase SDK sử dụng một 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 trình đơn đ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 của 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 đầu).
- 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
Tự động cài đặt
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 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ả một tiện ích VS Code được đi kèm) để giúp bạn quản lý giản đồ và xác định các truy vấn cũng như đột biến sẽ được dùng trong ứng dụng của bạn, đồng thời tạo các SDK có kiểu dữ liệu mạnh.
Sau khi chạy tập lệnh, VS Code sẽ tự động mở.
Sau khi thực hiện việc này một lần, bạn có thể khởi động 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 một 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 thành FriendlyFlixSDK
.
connectorId: "friendly-flix"
generate:
swiftSdk:
outputDir: "../../app"
package: "FriendlyFlixSDK"
observablePublisher: observableMacro
Sau đâ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 SDK Data Connect đã tạo sẽ được lưu trữ. Đườ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 là FriendlyFlixSDK
cho bạn và đặt gói này 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, rồi nhấp vào nút Start emulators (Khởi động trình mô phỏng).
Thao tác này sẽ khởi động Trình mô phỏng Firebase trong thiết bị đầu cuối tích hợp. Kết quả đầu ra 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 các phần phụ thuộc của 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), rồi nhập "FriendlyFlixApp" để nhanh chóng tìm thấy tệp) - Nhập Firebase, Firebase Auth, Firebase Data Connect và SDK đã tạo cho giản đồ của bạ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 Destination (Đí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à những 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à chỉ thị lược đồ 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 suốt 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 những 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-một với loại Movie
. Trong đó có thêm dữ liệu như đạo diễn của bộ 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 và giá trị mặc định được tạo tự động
Lược đồ này 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 riêng biệt. Ví dụ: trường id
trong loại Movie
sẽ tự động được điền bằng một 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 của phim
Sau khi xác định giản đồ, giờ đây, 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 rằng các 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 (cục bộ)) ở đầu tệp. Nhấp vào đây để chèn dữ liệu phim mô phỏng vào cơ sở dữ liệu của bạn.
- Kiểm tra thiết bị đầu cuối Data Connect Execution (Thực thi Data Connect) để xác nhận rằng dữ liệu đã được thêm thành công.
Sau 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 một truy vấn để truy xuất tất cả các bộ phim trong bảng movies
. Firebase Data Connect tạo mã cho một SDK an toàn về kiểu mà sau đó bạn có thể dùng để thực thi truy vấn và hiển thị các bộ phim đã 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 những trường cần tìm nạp. Trong FriendlyFlix, những màn hình hiển thị phim yêu cầu các trường sau: title
, description
, releaseYear
, rating
và imageUrl
. Ngoài ra, vì đây là một ứ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 (cục bộ)) để 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 phần Results (Kết quả) của thiết bị đầu cuối Data Connect Execution.
Kết nối truy vấn ListMovies với màn hình chính của ứng dụng
Giờ đây, sau 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 để ánh xạ từ ListMoviesQuery.Data.Movie
sang 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
rồi 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) để khởi 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 nổi bật, 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 các 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 vào việc cập nhật cách hiển thị phim trong phần nổi bật (là băng chuyền nổi bật ở đầu màn hình chính) và trong phần phim hàng đầu bên dưới.
Hiện tại, truy vấn ListMovies sẽ truy xuất tất cả các bộ phim. Để tối ưu hoá việc 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ề. Việc triển khai truy vấn ListMovies
hiện tại chưa hỗ trợ sẵn việc giới hạn kết quả. Việc thêm hỗ trợ cho việc giới hạn và sắp xếp là điều bạn sẽ thêm vào phần này.
Cải thiện truy vấn ListMovies
Mở queries.gql
rồi 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ề và sắp xếp tập kết quả theo cả mức phân loại 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
để tận 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 những 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 nổi bật 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 thẻ phim, họ sẽ thấy một số thông tin chi tiết về bộ 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ì... chi tiết!
Lý do là vì chúng tôi chỉ tìm nạp nhiều thông tin chi tiết về từng bộ phim khi cần để hiển thị phần tiêu đề phim và phần phim hàng đầu: 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ề bộ 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 được việc này, bạn sẽ cần thực hiện một số việc:
- Nâng cao giản đồ để hỗ trợ diễn viên và bài đánh giá về phim
- Viết các 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 chi tiết phim
Nâng cao giản đồ
Trong VS Code, hãy mở dataconnect/schema/schema.gql
rồi thêm các định nghĩa lược đồ 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 đối tượng
Sau khi cập nhật giản đồ, giờ đây, 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 rằng các 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 (cục bộ)) ở đầu tệp. Nhấp vào đây để chèn dữ liệu phim mô phỏng vào cơ sở dữ liệu của bạn.
- Kiểm tra thiết bị đầu cuối Data Connect Execution (Thực thi Data Connect) để xác nhận rằng dữ liệu đã được thêm thành công.
Sau khi có dữ liệu, hãy chuyển sang bước tiếp theo để xác định truy vấn 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 movieDetails
sao cho khớp với đoạn 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 chạy, hãy nhấn vào một thẻ phim để hiển thị thông tin chi tiết về phim. Ứng dụng sẽ hiển thị 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 cung cấp thông tin không được cá nhân hoá về phim và diễn viên. Trong các bước sau, bạn sẽ triển khai những 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.
Trước khi triển khai tính năng danh sách theo dõi, 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 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 ở 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ột màn hình nơi người dùng có thể đăng ký hoặc đăng nhập bằng email và mật khẩu.
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 cần thiết 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 đã 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 của bạn, hãy chuyển đến phần Xác thực rồi bật Xác thực Firebase. Sau đó, hãy bật trình cung cấp dịch vụ xác thực Email/Mật khẩu.
Trong thư mục dự án cục bộ, hãy tìm firebase.json
rồi 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 tiếp theo, bạn sẽ triển khai logic kết nối hoạt động xác thực người dùng với cơ sở dữ liệu. Việc 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ần đă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 quá trình 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 đoạn 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à một trình xử lý xác thực chung cho phép bạn sử dụng onSignUp
để đăng ký một lệnh đóng sẽ được gọi khi người dùng đã đăng nhập.
Trong lệnh đó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. Nhưng 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 một 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
rồi 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 đoạn 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 upsertUserMutation
Firebase Data Connect được tạo cho bạn để chèn một người dùng mới (hoặc cập nhật một người dùng hiện có 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 Firebase Authentication.
Xem cách thức hoạt động
Để xác minh rằng tính năng này hoạt độ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ý rồi đă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 một 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 Đọ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 Chạy cục bộ để xem tất cả người dùng trong bảng người dùng
- Trong ngăn Thực thi kết nối dữ liệu, giờ đây, 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 yêu thích của họ. 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.
Nâng cao giản đồ để hỗ trợ mục yêu thích
Loại FavoriteMovie
là một bảng kết hợp xử lý mối quan hệ nhiều-nhiều giữa người dùng và những bộ phim 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 yêu thích của người dùng, người dùng cần cho biết những bộ phim nào là bộ phim yêu thích của họ. Để làm được việc này, trước tiên, bạn cần thêm 2 độ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à phim 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
. Lệnh 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 bộ phim hiện tại trong cơ sở dữ liệu. Một bước cuối cùng còn thiếu là đảm bảo trạng thái giao diện người dùng được phản ánh cho phù hợp.
Xác định một 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 một phiên bản 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 xuất hiện trênMovieCardView
này có được đánh dấu là bộ phim yêu thích của 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 đả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 các bộ phim yêu thích
Trong bước cuối cùng của tính năng này, bạn sẽ triển khai việc tìm nạp các bộ phim yêu thích của người dùng để họ có thể xem các bộ 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ẽ xuất hiện 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ã để lập bản đồ 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
rồi 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 lấy thông tin 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 khung 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 đánh dấu yêu thích mà bạn vừa triển khai. Một số đ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 phim và thông tin chi tiết về phim
- Đảm bảo rằng 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 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 bộ phim là phim yêu thích. Biểu tượng trái tim sẽ chuyển sang màu đặc.
- Lặp lại thao tác này cho một vài bộ phim.
- Chuyển đến thẻ Thư viện. Giờ đây, bạn sẽ thấy danh sách tất cả những bộ phim mà bạn đã đánh dấu là 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 quan trọng 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 vào một dự án Firebase thực, 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 là ứng dụng cục bộ, tất cả dữ liệu đều nằm trong Bộ công cụ 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 quá trình 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 của 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 mục 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
Quan trọng: Nếu đây là lần đầu tiên bạn triển khai một giản đồ trong dự án của mình, thì quy trình này sẽ tạo một phiên bản Cloud SQL PostgreSQL. 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 VS Code, hãy nhấp vào Triển khai cho sản xuất. 2. Bạn có thể cần xem xét các thay đổi về giản đồ và phê duyệt những nội dung sửa đổi có khả năng gây hại. Bạn sẽ được nhắc: – Xem xét các thay đổi về giản đồ bằng cách sử dụng firebase dataconnect:sql:diff
– Khi 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 của bạn sẽ được cập nhật bằng giản đồ và dữ liệu được 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.
Giờ đây, 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, giống như khi bạn sử dụng 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 phát hành công khai 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ỏ chọn đối số khởi chạy
-useEmulator YES
.