
FirebaseUI cho SwiftUI là một thư viện hiện đại, ưu tiên SwiftUI, được xây dựng dựa trên Firebase Authentication, cung cấp các quy trình đăng nhập tạo sẵn cho ứng dụng của bạn.
FirebaseUI cho SwiftUI có các lợi ích sau:
- Giao diện người dùng mặc định theo ý kiến: thêm quy trình đăng nhập hoàn chỉnh bằng
AuthPickerView. - Có thể tuỳ chỉnh: hiển thị các nút mặc định trong bố cục của riêng bạn hoặc xây dựng trải nghiệm hoàn toàn tuỳ chỉnh.
- Liên kết tài khoản ẩn danh: nâng cấp người dùng ẩn danh (không bắt buộc) thay vì thay thế họ.
- Quản lý tài khoản: các quy trình tích hợp sẵn để đăng ký, khôi phục mật khẩu và quản lý tài khoản.
- Nhiều nhà cung cấp: email/mật khẩu, đường liên kết trong email, xác thực qua điện thoại, Apple, Google, Facebook, Twitter và các nhà cung cấp OAuth2/OIDC tiêu chuẩn.
- Các tính năng xác thực hiện đại: hỗ trợ tích hợp cho tính năng xác thực đa yếu tố (MFA) và API không đồng bộ/chờ.
Trước khi bắt đầu
Thêm Firebase vào dự án Apple. Hãy nhớ hoàn tất các bước SwiftUI.
Đảm bảo ứng dụng của bạn nhắm đến iOS 17 trở lên.
Lắp đặt
FirebaseUI cho SwiftUI được cung cấp dưới dạng một gói Swift. Để cài đặt gói trong dự án Xcode, hãy làm như sau:
Trong Xcode, hãy nhấp vào File > Add Package Dependencies (Tệp > Thêm phần phụ thuộc của gói).
Nhập URL của gói:
https://github.com/firebase/FirebaseUI-iOSTrong trình đơn Dependency Rule (Quy tắc phần phụ thuộc), hãy chọn Up to Next Major Version (Lên phiên bản lớn tiếp theo) và đặt phiên bản tối thiểu thành bản phát hành mới nhất.
Nhấp vào Add Package (Thêm gói), sau đó chọn các thư viện để thêm vào dự án của bạn.
Thư viện sau đây luôn là bắt buộc. Thư viện này bao gồm các phần phụ thuộc cốt lõi cũng như hỗ trợ đăng nhập bằng email-mật khẩu và đăng nhập bằng đường liên kết trong email.
FirebaseAuthSwiftUI
Nếu bạn muốn hỗ trợ các phương thức đăng nhập khác, hãy chọn một hoặc nhiều thư viện sau:
FirebaseAppleSwiftUI(Đăng nhập bằng Apple)FirebaseGoogleSwiftUI(Đăng nhập bằng Google)FirebaseFacebookSwiftUI(Đăng nhập bằng Facebook)FirebasePhoneAuthSwiftUI(Xác thực qua điện thoại)FirebaseTwitterSwiftUI(Đăng nhập bằng Twitter)FirebaseOAuthSwiftUI(Các nhà cung cấp OAuth và OIDC tiêu chuẩn như GitHub, Microsoft, Yahoo)
Nhấp vào Add Package (Thêm gói) để cài đặt các thư viện đã chọn.
Định cấu hình
AuthServicecủa FirebaseUI trong trình khởi tạo củaViewcấp cao nhất và truyền dịch vụ đến các chế độ xem dữ liệu trẻ em bằng môi trường.import FirebaseAuthSwiftUI import SwiftUI struct ContentView: View { let authService: AuthService init() { let configuration = AuthConfiguration() authService = AuthService(configuration: configuration) .withEmailSignIn() // Or whatever sign-in methods you want to support. // See the next section. } var body: some View { AuthPickerView { // AuthPickerView (the prebuilt View) or a custom View. Text("Welcome to your app!") } .environment(authService) } }
Thiết lập phương thức đăng nhập
Mỗi phương thức đăng nhập được hỗ trợ đều yêu cầu một số bước thiết lập bổ sung. Hãy mở rộng các phần bên dưới và làm theo hướng dẫn để thiết lập từng nhà cung cấp.
Địa chỉ email và mật khẩu
Trong phần Security > Authentication > Sign-in method (Bảo mật > Xác thực > Phương thức đăng nhập) của bảng điều khiển Firebase, hãy bật nhà cung cấp Email/Password (Email/Mật khẩu).
Đăng ký nhà cung cấp trong thực thể
AuthService:let authService = AuthService() .withEmailSignIn()
Xác thực đường liên kết trong email
Cách đăng nhập bằng đường liên kết trong email mà không cần mật khẩu:
Trong phần Security > Authentication > Sign-in method (Bảo mật > Xác thực > Phương thức đăng nhập) của bảng điều khiển Firebase, hãy bật Email/Password (Email/Mật khẩu), sau đó bật tính năng đăng nhập bằng đường liên kết trong email. Xin lưu ý rằng bạn phải bật tính năng đăng nhập bằng email hoặc mật khẩu để sử dụng tính năng đăng nhập bằng đường liên kết trong email.
Thêm miền của đường liên kết vào Miền được uỷ quyền.
Định cấu hình
ActionCodeSettings, truyền vàoAuthConfigurationvà đăng ký nhà cung cấp:let actionCodeSettings = ActionCodeSettings() actionCodeSettings.handleCodeInApp = true actionCodeSettings.url = URL(string: "https://yourapp.firebaseapp.com") guard let bundleID = Bundle.main.bundleIdentifier else { fatalError("Missing bundle identifier for email link authentication setup.") } actionCodeSettings.setIOSBundleID(bundleID) let configuration = AuthConfiguration( emailLinkSignInActionCodeSettings: actionCodeSettings ) let authService = AuthService(configuration: configuration) .withEmailLinkSignIn()Trong cùng một
AppDelegatemà bạn gọiFirebaseApp.configure(), hãy thêm logic vào phương thứcapplication(_:open:options:)trả vềtruekhi URL được mở là đường liên kết đăng nhập Firebase Authentication. Logic này cho biết rằng đường liên kết đã được FirebaseUI xử lý và không nên được xử lý bởi các trình xử lý đường liên kết khác.import FacebookCore import FirebaseAuth import UIKit class AppDelegate: NSObject, UIApplicationDelegate { func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { FirebaseApp.configure() return true } func application( _ application: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:] ) -> Bool { if Auth.auth().canHandle(url) { return true } return false } }Nếu bạn tạo chế độ xem tuỳ chỉnh, hãy gọi
authService.handleSignInLink(url:)khi đường liên kết mở ứng dụng của bạn.
Apple
Cách sử dụng tính năng Đăng nhập bằng Apple:
Định cấu hình tính năng Đăng nhập bằng Apple:
- Bật tính năng Đăng nhập bằng Apple cho ứng dụng của bạn trên trang Certificates, Identifiers & Profiles (Chứng chỉ, giá trị nhận dạng và hồ sơ) trên trang web dành cho nhà phát triển của Apple.
- Liên kết trang web với ứng dụng của bạn như mô tả trong phần đầu tiên của bài viết Định cấu hình tính năng Đăng nhập bằng Apple cho web. Khi được nhắc, hãy đăng ký URL sau đây làm URL trả về:
Bạn có thể lấy mã dự án Firebase trên trang cài đặt bảng điều khiển Firebase. Khi bạn hoàn tất, hãy ghi lại Mã dịch vụ mới của bạn. Bạn sẽ cần mã này trong phần tiếp theo.https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/__/auth/handler
- Tạo khoá riêng tư cho tính năng Đăng nhập bằng Apple. Bạn sẽ cần khoá riêng tư và mã khoá mới trong phần tiếp theo.
- Nếu bạn sử dụng bất kỳ tính năng nào của Firebase Authentication để gửi email cho người dùng, bao gồm cả tính năng đăng nhập bằng đường liên kết trong email, xác minh địa chỉ email, thu hồi thay đổi tài khoản và các tính năng khác, hãy định cấu hình dịch vụ chuyển tiếp email riêng tư của Apple và đăng ký
noreply@YOUR_FIREBASE_PROJECT_ID.firebaseapp.com(hoặc miền mẫu email tuỳ chỉnh của bạn) để Apple có thể chuyển tiếp email do Firebase Authentication gửi đến các địa chỉ email ẩn danh của Apple.
Trong phần Security > Authentication > Sign-in method (Bảo mật > Xác thực > Phương thức đăng nhập) của bảng điều khiển Firebase, hãy bật Apple.
- Chỉ định Mã dịch vụ mà bạn đã tạo trong phần trước.
- Trong phần cấu hình quy trình mã OAuth, hãy chỉ định Mã nhóm Apple, khoá riêng tư và mã khoá mà bạn đã tạo trong phần trước.
Trong Xcode, hãy mở phần Signing & Capabilities (Ký và chức năng) của trình chỉnh sửa dự án rồi thêm chức năng Sign in with Apple (Đăng nhập bằng Apple).
Đăng ký nhà cung cấp trong thực thể
AuthService:let authService = AuthService() .withAppleSignIn()
Cách sử dụng tính năng Đăng nhập bằng Google:
Trong phần Security > Authentication > Sign-in method (Bảo mật > Xác thực > Phương thức đăng nhập) của bảng điều khiển Firebase, hãy bật nhà cung cấp Google.
Tải bản sao mới của tệp
GoogleService-Info.plistcủa dự án xuống và sao chép tệp đó vào dự án Xcode của bạn. Ghi đè mọi phiên bản hiện có bằng phiên bản mới.Thêm lược đồ URL tuỳ chỉnh vào dự án Xcode:
Mở cấu hình dự án: nhấp vào tên dự án trong chế độ xem dạng cây bên trái. Chọn ứng dụng của bạn trong mục TARGETS (MỤC TIÊU), sau đó chọn thẻ Info (Thông tin) rồi mở rộng mục URL Types (Loại URL).
Nhấp vào nút + rồi thêm một lược đồ URL cho mã ứng dụng khách đảo ngược của bạn. Để tìm giá trị này, hãy mở tệp cấu hình
và tìm khoáGoogleService-Info.plist REVERSED_CLIENT_ID. Sao chép giá trị của khoá đó, rồi dán vào hộp Lược đồ URL trên trang cấu hình. Giữ nguyên các trường khác.Khi hoàn tất, cấu hình của bạn sẽ có dạng như sau (nhưng có các giá trị dành riêng cho ứng dụng):

Đăng ký nhà cung cấp trong thực thể
AuthService:let authService = AuthService() .withGoogleSignIn()
Cách sử dụng tính năng Đăng nhập bằng Facebook:
Thiết lập SDK Đăng nhập bằng Facebook cho iOS bằng cách làm theo hướng dẫn trên trang web Meta for Developers. Bỏ qua bước cuối cùng, "Thêm tính năng Đăng nhập bằng Facebook vào mã của bạn".
Trong phần Security > Authentication > Sign-in method (Bảo mật > Xác thực > Phương thức đăng nhập) của bảng điều khiển Firebase, hãy bật nhà cung cấp Facebook. Bạn sẽ cần có Mã ứng dụng và Khoá bí mật của ứng dụng trên Facebook từ trang web Meta for Developers.
Đăng ký nhà cung cấp trong thực thể
AuthService:let authService = AuthService() .withFacebookSignIn()
Số điện thoại
Cách sử dụng phương thức xác thực qua điện thoại:
Trong phần Security > Authentication > Sign-in method (Bảo mật > Xác thực > Phương thức đăng nhập) của bảng điều khiển Firebase, hãy bật nhà cung cấp Phone (Điện thoại).
Định cấu hình APN cho ứng dụng của bạn theo hướng dẫn trong phần Bắt đầu nhận thông báo tự động.
Thêm lược đồ URL tuỳ chỉnh vào dự án Xcode:
Mở cấu hình dự án: nhấp vào tên dự án trong chế độ xem dạng cây bên trái. Chọn ứng dụng của bạn trong mục TARGETS (MỤC TIÊU), sau đó chọn thẻ Info (Thông tin) rồi mở rộng mục URL Types (Loại URL).
Nhấp vào nút + rồi thêm Mã ứng dụng được mã hoá làm lược đồ URL. Để tìm giá trị này, hãy mở phần Cài đặt > Chung trong bảng điều khiển Firebase.
Khi hoàn tất, cấu hình của bạn sẽ có dạng như sau (nhưng có các giá trị dành riêng cho ứng dụng):

Trong cùng một
AppDelegatemà bạn gọiFirebaseApp.configure(), hãy thêm trình xử lý mã thông báo APN:import FacebookCore import FirebaseAuth import UIKit class AppDelegate: NSObject, UIApplicationDelegate { func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { FirebaseApp.configure() return true } func application( _ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data ) { #if DEBUG Auth.auth().setAPNSToken(deviceToken, type: .sandbox) #else Auth.auth().setAPNSToken(deviceToken, type: .prod) #endif } }Đăng ký nhà cung cấp trong thực thể
AuthService:let authService = AuthService() .withPhoneSignIn()
Twitter (X)
Cách sử dụng tính năng Đăng nhập bằng Twitter:
Tạo thông tin xác thực API X bằng cách làm theo hướng dẫn trên trang web Nhà phát triển X.
Trong phần Security > Authentication > Sign-in method (Bảo mật > Xác thực > Phương thức đăng nhập) của bảng điều khiển Firebase, hãy bật nhà cung cấp Twitter. Bạn sẽ cần khoá API và mã thông báo bí mật cho API từ X Developer Console.
Đăng ký nhà cung cấp trong thực thể
AuthService:let authService = AuthService() .withTwitterSignIn()
Nhà cung cấp OAuth2 và OIDC tiêu chuẩn
FirebaseUI cũng hỗ trợ các nhà cung cấp OAuth tích hợp sẵn như GitHub, Microsoft và Yahoo, cũng như các nhà cung cấp OIDC tuỳ chỉnh được định cấu hình trong Firebase Authentication.
let authService = AuthService()
.withOAuthSignIn(OAuthProviderSwift.github())
.withOAuthSignIn(OAuthProviderSwift.microsoft())
.withOAuthSignIn(OAuthProviderSwift.yahoo())
Đối với nhà cung cấp OIDC tuỳ chỉnh, trước tiên, hãy định cấu hình nhà cung cấp trong Firebase Authentication, sau đó tạo một OAuthProviderSwift bằng mã nhận dạng nhà cung cấp và cấu hình nút:
let lineProvider = OAuthProviderSwift(
providerId: "oidc.line",
buttonLabel: "Sign in with LINE",
displayName: "LINE",
iconSystemName: "person.crop.circle.badge.checkmark",
buttonBackgroundColor: .green,
buttonForegroundColor: .white
)
let authService = AuthService()
.withOAuthSignIn(lineProvider)
Sử dụng chế độ xem xác thực tạo sẵn
FirebaseUI cho SwiftUI cung cấp AuthPickerView, một giao diện người dùng xác thực được tạo sẵn và có sẵn ý kiến, xử lý toàn bộ quy trình xác thực cho bạn. Đây là cách dễ nhất để thêm tính năng xác thực vào ứng dụng của bạn.
Ví dụ
Dưới đây là ví dụ về cách sử dụng AuthPickerView, với nhiều nhà cung cấp và tuỳ chọn cấu hình:
import FirebaseAppleSwiftUI
import FirebaseAuthSwiftUI
import FirebaseGoogleSwiftUI
import SwiftUI
struct ContentView: View {
let authService: AuthService
init() {
// Create configuration with options
let configuration = AuthConfiguration(
tosUrl: URL(string: "https://example.com/tos"),
privacyPolicyUrl: URL(string: "https://example.com/privacy"),
shouldAutoUpgradeAnonymousUsers: true
)
// Initialize AuthService with multiple providers
authService = AuthService(configuration: configuration)
.withEmailSignIn()
.withAppleSignIn()
.withGoogleSignIn()
}
var body: some View {
AuthPickerView {
authenticatedContent
}
.environment(authService)
}
var authenticatedContent: some View {
NavigationStack {
VStack(spacing: 20) {
if authService.authenticationState == .authenticated {
Text("Authenticated")
Button("Manage Account") {
authService.isPresented = true
}
.buttonStyle(.bordered)
Button("Sign Out") {
Task {
try? await authService.signOut()
}
}
.buttonStyle(.borderedProminent)
} else {
Text("Not Authenticated")
Button("Sign In") {
authService.isPresented = true
}
.buttonStyle(.borderedProminent)
}
}
.navigationTitle("My App")
}
.onChange(of: authService.authenticationState) { _, newValue in
// Automatically show auth UI when not authenticated
if newValue != .authenticating {
authService.isPresented = (newValue == .unauthenticated)
}
}
}
}
Tuỳ chỉnh thông thường
Mặc dù tất cả tham số AuthConfiguration đều không bắt buộc, nhưng hầu hết các ứng dụng đều tuỳ chỉnh ít nhất các chế độ cài đặt sau:
let configuration = AuthConfiguration(
logo: ImageResource.exampleLogoAsset,
customStringsBundle: .main,
tosUrl: URL(string: "https://example.com/tos"),
privacyPolicyUrl: URL(string: "https://example.com/privacy"),
)
logo: hình ảnh biểu trưng hiển thị trên trang xác thực. Để biết thông tin về cách thêm thành phần hình ảnh của riêng bạn, hãy xem bài viết Thêm hình ảnh vào dự án Xcode.customStringsBundle: sử dụng chuỗi tuỳ chỉnh từ Gói đã chỉ định. Tệp này được dùng để bản địa hoá, nhưng cũng dùng để tuỳ chỉnh các chuỗi mặc định màAuthPickerViewsử dụng. Ví dụ: để đặt thông báo hiển thị ở đầu trang xác thực, hãy tạoLocalizable.stringscó nội dung:"Sign in with Firebase" = "Sign in to use ExampleApp";
Nội dung trong chế độ xem tạo sẵn
Khi sử dụng AuthPickerView, bạn sẽ được:
- Trình bày trang tính: Giao diện người dùng xác thực xuất hiện dưới dạng trang tính phương thức
- Điều hướng tích hợp sẵn: Tự động điều hướng giữa các màn hình đăng nhập, khôi phục mật khẩu, MFA, đường liên kết qua email và xác minh qua điện thoại
- Quản lý trạng thái xác thực: Tự động chuyển đổi giữa giao diện người dùng xác thực và nội dung của bạn dựa trên
authService.authenticationState - Kiểm soát thông qua
isPresented: Kiểm soát thời điểm trang xác thực xuất hiện bằng cách đặtauthService.isPresented = true/false
Hành vi có chủ đích
AuthPickerView mặc định có ý kiến về cách xử lý một số trường hợp phức tạp:
1. Giải quyết xung đột tài khoản
Khi xảy ra xung đột tài khoản (ví dụ: đăng nhập bằng thông tin xác thực đã được liên kết với một tài khoản khác), AuthPickerView sẽ tự động xử lý:
- Xung đột khi nâng cấp ẩn danh: Nếu bạn bật
shouldAutoUpgradeAnonymousUsersvà xảy ra xung đột trong quá trình nâng cấp ẩn danh, thì hệ thống sẽ tự động đăng xuất người dùng ẩn danh và đăng nhập bằng thông tin xác thực mới. - Xung đột khác: Đối với xung đột thông tin xác thực giữa các tài khoản không ẩn danh, hệ thống sẽ lưu trữ thông tin xác thực đang chờ xử lý và cố gắng liên kết thông tin đó sau khi đăng nhập thành công.
Việc này do AccountConflictModifier xử lý, được áp dụng ở cấp NavigationStack.
2. Xác thực đa yếu tố (MFA)
Khi bạn bật MFA trong cấu hình:
- Tự động phát hiện khi cần có MFA trong quá trình đăng nhập
- Trình bày màn hình giải quyết MFA thích hợp (SMS hoặc TOTP)
- Xử lý quy trình đăng ký và quản lý MFA
- Hỗ trợ cả phương thức xác thực bằng mật khẩu một lần (OTP) qua SMS và mật khẩu một lần theo thời gian (TOTP)
3. Xử lý lỗi
Chế độ xem mặc định bao gồm tính năng xử lý lỗi tích hợp:
- Hiện thông báo lỗi thân thiện với người dùng trong hộp thoại cảnh báo
- Tự động lọc ra các lỗi được xử lý nội bộ (ví dụ: lỗi huỷ, xung đột được xử lý tự động)
- Sử dụng thông báo lỗi đã bản địa hoá thông qua
StringUtils - Lỗi được truyền qua khoá môi trường
reportError
4. Đăng nhập bằng đường liên kết trong email
Khi bạn định cấu hình tính năng đăng nhập bằng đường liên kết trong email:
- Tự động lưu trữ địa chỉ email trong bộ nhớ của ứng dụng
- Xử lý thao tác điều hướng liên kết sâu từ email
- Quản lý toàn bộ quy trình xác minh email
- Hỗ trợ nâng cấp người dùng ẩn danh qua đường liên kết trong email
5. Tự động nâng cấp người dùng ẩn danh
Khi shouldAutoUpgradeAnonymousUsers được bật:
- Tự động tìm cách liên kết tài khoản ẩn danh với thông tin đăng nhập mới
- Bảo toàn dữ liệu người dùng bằng cách nâng cấp thay vì thay thế các phiên ẩn danh
- Xử lý xung đột khi nâng cấp một cách linh hoạt
6. Xác thực lại trong chế độ xem mặc định
Các thao tác nhạy cảm như xoá tài khoản, cập nhật mật khẩu hoặc huỷ đăng ký các yếu tố xác thực đa yếu tố (MFA) đều yêu cầu xác thực gần đây. Khi sử dụng chế độ xem mặc định, quá trình xác thực lại sẽ được xử lý tự động dựa trên nhà cung cấp dịch vụ đăng nhập của người dùng.
Khi một thao tác nhạy cảm yêu cầu xác thực lại, các chế độ xem mặc định sẽ tự động:
Nhà cung cấp OAuth (Google, Apple, Facebook, Twitter, v.v.): Hiển thị cảnh báo yêu cầu người dùng xác nhận, sau đó tự động lấy thông tin xác thực mới và hoàn tất thao tác.
Email/Mật khẩu: Hiển thị một trang tính nhắc người dùng nhập mật khẩu trước khi tiếp tục.
Đường liên kết trong email: Hiển thị cảnh báo yêu cầu gửi email xác minh, sau đó hiển thị một trang tính có hướng dẫn kiểm tra email. Người dùng nhấn vào đường liên kết trong email để hoàn tất quy trình xác thực lại.
Điện thoại: Hiển thị cảnh báo giải thích rằng cần xác minh, sau đó hiển thị một trang tính để xác minh mã SMS.
Thao tác này sẽ tự động thử lại sau khi xác thực lại thành công. Bạn không cần thêm mã khi sử dụng AuthPickerView hoặc các chế độ xem quản lý tài khoản tích hợp sẵn (UpdatePasswordView, SignedInView, v.v.).
Nâng cao: Tạo chế độ xem xác thực tuỳ chỉnh
Nếu cần kiểm soát nhiều hơn đối với giao diện người dùng hoặc quy trình điều hướng, bạn có thể tạo chế độ xem xác thực tuỳ chỉnh của riêng mình trong khi vẫn tận dụng AuthService cho logic xác thực.
Bạn có thể kết hợp các thành phần của FirebaseUI với logic tuỳ chỉnh theo nhiều cách. Các phần sau đây trình bày ví dụ về một số phương pháp tuỳ chỉnh mà bạn có thể sử dụng.
Cách 1: Nút tuỳ chỉnh có registerProvider()
Để có toàn quyền kiểm soát giao diện của nút, bạn có thể tạo phương thức triển khai AuthProviderUI tuỳ chỉnh của riêng mình để gói bất kỳ nhà cung cấp nào và trả về chế độ xem nút tuỳ chỉnh.
Tạo giao diện người dùng của trình cung cấp tuỳ chỉnh
Sau đây là ví dụ về cách tạo nút Twitter tuỳ chỉnh:
import FirebaseAuthSwiftUI
import FirebaseTwitterSwiftUI
import SwiftUI
// Step 1: Create your custom button view
struct CustomTwitterButton: View {
let provider: TwitterProviderSwift
@Environment(AuthService.self) private var authService
@Environment(\.mfaHandler) private var mfaHandler
var body: some View {
Button {
Task {
do {
let outcome = try await authService.signIn(provider)
// Handle MFA if required
if case let .mfaRequired(mfaInfo) = outcome,
let onMFA = mfaHandler {
onMFA(mfaInfo)
}
} catch {
// Do Something Else
}
}
} label: {
HStack { // Your custom icon
Text("Sign in with Twitter")
.fontWeight(.semibold)
}
.frame(maxWidth: .infinity)
.padding()
.background(
LinearGradient(
colors: [Color.blue, Color.cyan],
startPoint: .leading,
endPoint: .trailing
)
)
.foregroundColor(.white)
.cornerRadius(12)
.shadow(radius: 4)
}
}
}
// Step 2: Create a custom AuthProviderUI wrapper
class CustomTwitterProviderAuthUI: AuthProviderUI {
private let typedProvider: TwitterProviderSwift
var provider: AuthProviderSwift { typedProvider }
let id: String = "twitter.com"
init(provider: TwitterProviderSwift = TwitterProviderSwift()) {
typedProvider = provider
}
@MainActor func authButton() -> AnyView {
AnyView(CustomTwitterButton(provider: typedProvider))
}
}
// Step 3: Use it in your app
struct ContentView: View {
let authService: AuthService
init() {
let configuration = AuthConfiguration()
authService = AuthService(configuration: configuration)
// Register your custom provider UI
authService.registerProvider(
providerWithButton: CustomTwitterProviderAuthUI()
)
authService.isPresented = true
}
var body: some View {
AuthPickerView {
usersApp
}
.environment(authService)
}
var usersApp: some View {
NavigationStack {
VStack {
Button {
authService.isPresented = true
} label: {
Text("Authenticate")
}
}
}
}
}
Ví dụ về nút tuỳ chỉnh đơn giản
Bạn cũng có thể tạo các nút tuỳ chỉnh đơn giản hơn cho bất kỳ nhà cung cấp nào:
import FirebaseAuthSwiftUI
import FirebaseGoogleSwiftUI
import FirebaseAppleSwiftUI
import SwiftUI
// Custom Google Provider UI
class CustomGoogleProviderAuthUI: AuthProviderUI {
private let typedProvider: GoogleProviderSwift
var provider: AuthProviderSwift { typedProvider }
let id: String = "google.com"
init() {
typedProvider = GoogleProviderSwift()
}
@MainActor func authButton() -> AnyView {
AnyView(CustomGoogleButton(provider: typedProvider))
}
}
struct CustomGoogleButton: View {
let provider: GoogleProviderSwift
@Environment(AuthService.self) private var authService
var body: some View {
Button {
Task {
try? await authService.signIn(provider)
}
} label: {
HStack {
Image(systemName: "g.circle.fill")
Text("My Custom Google Button")
}
.frame(maxWidth: .infinity)
.padding()
.background(Color.purple) // Your custom color
.foregroundColor(.white)
.cornerRadius(10)
}
}
}
// Then use it
struct ContentView: View {
let authService: AuthService
init() {
let configuration = AuthConfiguration()
authService = AuthService(configuration: configuration)
.withAppleSignIn() // Use default Apple button
// Use custom Google button
authService.registerProvider(
providerWithButton: CustomGoogleProviderAuthUI()
)
}
var body: some View {
AuthPickerView {
Text("App Content")
}
.environment(authService)
}
}
Phương pháp này áp dụng cho tất cả nhà cung cấp: Google, Apple, Twitter, Facebook, Điện thoại và nhà cung cấp OAuth. Bạn chỉ cần tạo chế độ xem nút tuỳ chỉnh và gói chế độ xem đó trong một lớp tuân thủ AuthProviderUI.
Cách 2: Các nút mặc định có thành phần hiển thị tuỳ chỉnh
Bạn có thể sử dụng AuthService.renderButtons() và bỏ qua AuthPickerView để hiển thị các nút xác thực mặc định trong khi cung cấp bố cục và cách điều hướng của riêng bạn:
import FirebaseAuthSwiftUI
import FirebaseGoogleSwiftUI
import FirebaseAppleSwiftUI
import SwiftUI
struct CustomAuthView: View {
@Environment(AuthService.self) private var authService
var body: some View {
VStack(spacing: 30) {
// Your custom logo/branding
Image("app-logo")
.resizable()
.frame(width: 150, height: 150)
Text("Welcome to My App")
.font(.largeTitle)
.fontWeight(.bold)
Text("Sign in to continue")
.font(.subheadline)
.foregroundStyle(.secondary)
// Render default auth buttons
authService.renderButtons(spacing: 12)
.padding()
}
.padding()
}
}
struct ContentView: View {
init() {
let configuration = AuthConfiguration()
authService = AuthService(configuration: configuration)
.withGoogleSignIn()
.withAppleSignIn()
}
let authService: AuthService
var body: some View {
NavigationStack {
if authService.authenticationState == .authenticated {
Text("Authenticated!")
} else {
CustomAuthView()
}
}
.environment(authService)
}
}
Cách 3: Chế độ xem tuỳ chỉnh có tính năng điều hướng tuỳ chỉnh
Để có toàn quyền kiểm soát toàn bộ quy trình, bạn có thể bỏ qua AuthPickerView và xây dựng hệ thống điều hướng của riêng mình:
import FirebaseAuth
import FirebaseAuthSwiftUI
import FirebaseGoogleSwiftUI
import SwiftUI
enum CustomAuthRoute {
case signIn
case phoneVerification
case mfaResolution
}
struct ContentView: View {
private let authService: AuthService
@State private var navigationPath: [CustomAuthRoute] = []
@State private var errorMessage: String?
init() {
let configuration = AuthConfiguration()
self.authService = AuthService(configuration: configuration)
.withGoogleSignIn()
.withPhoneSignIn()
}
var body: some View {
NavigationStack(path: $navigationPath) {
Group {
if authService.authenticationState == .authenticated {
authenticatedView
} else {
customSignInView
}
}
.navigationDestination(for: CustomAuthRoute.self) { route in
switch route {
case .signIn:
customSignInView
case .phoneVerification:
customPhoneVerificationView
case .mfaResolution:
customMFAView
}
}
}
.environment(authService)
.alert("Error", isPresented: .constant(errorMessage != nil)) {
Button("OK") {
errorMessage = nil
}
} message: {
Text(errorMessage ?? "")
}
}
var customSignInView: some View {
VStack(spacing: 20) {
Text("Custom Sign In")
.font(.title)
Button("Sign in with Google") {
Task {
do {
let provider = GoogleProviderSwift(clientID: Auth.auth().app?.options.clientID ?? "")
let outcome = try await authService.signIn(provider)
// Handle MFA if required
if case .mfaRequired = outcome {
navigationPath.append(.mfaResolution)
}
} catch {
errorMessage = error.localizedDescription
}
}
}
.buttonStyle(.borderedProminent)
Button("Phone Sign In") {
navigationPath.append(.phoneVerification)
}
.buttonStyle(.bordered)
}
.padding()
}
var customPhoneVerificationView: some View {
Text("Custom Phone Verification View")
// Implement your custom phone auth UI here
}
var customMFAView: some View {
Text("Custom MFA Resolution View")
// Implement your custom MFA UI here
}
var authenticatedView: some View {
VStack(spacing: 20) {
Text("Welcome!")
Text("Email: \(authService.currentUser?.email ?? "N/A")")
Button("Sign Out") {
Task {
try? await authService.signOut()
}
}
.buttonStyle(.borderedProminent)
}
}
}
Những điểm quan trọng cần lưu ý đối với khung hiển thị tuỳ chỉnh
Khi tạo chế độ xem tuỳ chỉnh, bạn cần tự xử lý một số việc mà AuthPickerView tự động xử lý:
- Xung đột tài khoản: Triển khai chiến lược giải quyết xung đột của riêng bạn bằng cách sử dụng
AuthServiceError.accountConflict - Xử lý MFA: Kiểm tra
SignInOutcomeđể tìm.mfaRequiredvà xử lý MFA theo cách thủ công - Nâng cấp người dùng ẩn danh: Xử lý việc liên kết tài khoản ẩn danh nếu
shouldAutoUpgradeAnonymousUsersđược bật - Trạng thái điều hướng: Quản lý việc điều hướng giữa các màn hình xác thực (xác minh qua điện thoại, khôi phục mật khẩu, v.v.)
- Trạng thái tải: Hiển thị chỉ báo tải trong các thao tác xác thực không đồng bộ bằng cách quan sát
authService.authenticationState - Xác thực lại: Xử lý lỗi xác thực lại đối với các thao tác nhạy cảm (xem phần Xác thực lại trong Chế độ xem tuỳ chỉnh bên dưới)
Xác thực lại trong thành phần hiển thị tuỳ chỉnh
Khi tạo khung hiển thị tuỳ chỉnh, hãy xử lý việc xác thực lại bằng cách phát hiện các lỗi cụ thể và triển khai quy trình của riêng bạn. Các thao tác nhạy cảm sẽ gửi bốn loại lỗi xác thực lại, mỗi loại chứa thông tin bối cảnh.
Mẫu triển khai
Nhà cung cấp OAuth (Google, Apple, Facebook, Twitter, v.v.):
Bắt lỗi và gọi reauthenticate(context:) để tự động xử lý quy trình OAuth:
do {
try await authService.deleteUser()
} catch let error as AuthServiceError {
if case .oauthReauthenticationRequired(let context) = error {
try await authService.reauthenticate(context: context)
try await authService.deleteUser() // Retry operation
}
}
Email/Mật khẩu:
Bắt lỗi, nhắc nhập mật khẩu, tạo thông tin xác thực và gọi reauthenticate(with:):
do {
try await authService.updatePassword(to: newPassword)
} catch let error as AuthServiceError {
if case .emailReauthenticationRequired(let context) = error {
// Show your password prompt UI
let password = await promptUserForPassword()
let credential = EmailAuthProvider.credential(
withEmail: context.email,
password: password
)
try await authService.reauthenticate(with: credential)
try await authService.updatePassword(to: newPassword) // Retry
}
}
Điện thoại:
Bắt lỗi, xác minh điện thoại, tạo thông tin xác thực và gọi reauthenticate(with:):
do {
try await authService.deleteUser()
} catch let error as AuthServiceError {
if case .phoneReauthenticationRequired(let context) = error {
// Send verification code
let verificationId = try await authService.verifyPhoneNumber(
phoneNumber: context.phoneNumber
)
// Show your SMS code input UI
let code = await promptUserForSMSCode()
let credential = PhoneAuthProvider.provider().credential(
withVerificationID: verificationId,
verificationCode: code
)
try await authService.reauthenticate(with: credential)
try await authService.deleteUser() // Retry
}
}
Email Link:
Bắt lỗi, gửi email xác minh và xử lý URL đến:
do {
try await authService.updatePassword(to: newPassword)
} catch let error as AuthServiceError {
if case .emailLinkReauthenticationRequired(let context) = error {
// Send verification email
try await authService.sendEmailSignInLink(
email: context.email,
isReauth: true
)
// Show your "Check your email" UI
await showCheckEmailUI()
// When user taps the link, it opens your app with a URL
// Handle it in your URL handler:
// try await authService.handleSignInLink(url: url)
// The handleSignInLink method automatically completes reauthentication
try await authService.updatePassword(to: newPassword) // Retry
}
}
Tất cả đối tượng bối cảnh xác thực lại đều bao gồm thuộc tính .displayMessage cho văn bản mà người dùng nhìn thấy.
Nhà cung cấp OAuth tuỳ chỉnh
Bạn có thể tạo nhà cung cấp OAuth tuỳ chỉnh cho các dịch vụ ngoài những dịch vụ tích hợp sẵn:
⚠️ Quan trọng: Bạn phải định cấu hình nhà cung cấp OIDC (OpenID Connect) trong phần cài đặt Xác thực của dự án Firebase thì mới có thể sử dụng. Trong Bảng điều khiển của Firebase, hãy chuyển đến phần Authentication → Sign-in method (Xác thực → Phương thức đăng nhập) rồi thêm nhà cung cấp OIDC của bạn cùng với thông tin xác thực bắt buộc (Mã ứng dụng khách, Khoá bí mật của ứng dụng khách, URL của nhà phát hành). Bạn cũng phải đăng ký URI chuyển hướng OAuth do Firebase cung cấp trong bảng điều khiển dành cho nhà phát triển của nhà cung cấp. Hãy xem tài liệu về OIDC của Firebase để biết hướng dẫn thiết lập chi tiết.
import FirebaseAuthSwiftUI
import FirebaseOAuthSwiftUI
import SwiftUI
struct ContentView: View {
let authService: AuthService
init() {
let configuration = AuthConfiguration()
authService = AuthService(configuration: configuration)
.withOAuthSignIn(
OAuthProviderSwift(
providerId: "oidc.line", // LINE OIDC provider
scopes: ["profile", "openid", "email"], // LINE requires these scopes
displayName: "Sign in with LINE",
buttonIcon: Image("line-logo"),
buttonBackgroundColor: .green,
buttonForegroundColor: .white
)
)
.withOAuthSignIn(
OAuthProviderSwift(
providerId: "oidc.custom-provider",
scopes: ["profile", "openid"],
displayName: "Sign in with Custom",
buttonIcon: Image(systemName: "person.circle"),
buttonBackgroundColor: .purple,
buttonForegroundColor: .white
)
)
}
var body: some View {
AuthPickerView {
Text("App Content")
}
.environment(authService)
}
}