
FirebaseUI dla SwiftUI to nowoczesna biblioteka oparta na SwiftUI, która jest zbudowana na podstawie Firebase Authentication i zapewnia gotowe przepływy logowania w aplikacji.
FirebaseUI dla SwiftUI ma te zalety:
- Opinie na temat domyślnego interfejsu: dodaj pełny proces logowania za pomocą
AuthPickerView. - Możliwość dostosowania: możesz renderować domyślne przyciski we własnym układzie lub stworzyć w pełni niestandardowe rozwiązanie.
- Łączenie kont anonimowych: opcjonalne zastępowanie użytkowników anonimowych zamiast ich usuwania.
- Zarządzanie kontem: wbudowane procesy rejestracji, odzyskiwania hasła i zarządzania kontem.
- Wielu dostawców: e-mail i hasło, link w e-mailu, uwierzytelnianie za pomocą telefonu, Apple, Google, Facebook, Twitter i standardowi dostawcy OAuth2/OIDC.
- Nowoczesne funkcje uwierzytelniania: wbudowana obsługa uwierzytelniania wielopoziomowego (MFA) i interfejsów API async/await.
Zanim zaczniesz
Dodaj Firebase do projektu Apple. Wykonaj kroki dotyczące SwiftUI.
Upewnij się, że Twoja aplikacja jest przeznaczona na system iOS 17 lub nowszy.
Instalacja
FirebaseUI dla SwiftUI jest udostępniany jako pakiet Swift. Aby zainstalować pakiet w projekcie Xcode, wykonaj te czynności:
W Xcode kliknij File > Add Package Dependencies (Plik > Dodaj zależności pakietu).
Wpisz adres URL pakietu:
https://github.com/firebase/FirebaseUI-iOSW menu Reguła zależności wybierz Do następnej wersji głównej i ustaw minimalną wersję na najnowszą wersję.
Kliknij Add Package (Dodaj pakiet), a następnie wybierz biblioteki, które chcesz dodać do projektu.
Ta biblioteka jest zawsze wymagana. Obejmuje podstawowe zależności, a także obsługę logowania się za pomocą adresu e-mail i hasła oraz logowania się za pomocą linku w e-mailu.
FirebaseAuthSwiftUI
Jeśli chcesz obsługiwać inne metody logowania, wybierz też co najmniej jedną z tych bibliotek:
FirebaseAppleSwiftUI(Zaloguj się przez Apple)FirebaseGoogleSwiftUI(Zaloguj się przez Google)FirebaseFacebookSwiftUI(Zaloguj się przez Facebooka)FirebasePhoneAuthSwiftUI(Uwierzytelnianie za pomocą telefonu)FirebaseTwitterSwiftUI(Zaloguj się przez Twittera)FirebaseOAuthSwiftUI(standardowi dostawcy OAuth i OIDC, np. GitHub, Microsoft, Yahoo)
Aby zainstalować wybrane biblioteki, kliknij Dodaj pakiet.
Skonfiguruj
AuthServiceFirebaseUI w inicjatorze najwyższego poziomuViewi przekaż usługę do widoków podrzędnych za pomocą środowiska.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) } }
Konfigurowanie metod logowania
Każda z obsługiwanych metod logowania wymaga wykonania dodatkowych czynności konfiguracyjnych. Rozwiń sekcje poniżej i postępuj zgodnie z instrukcjami, aby skonfigurować poszczególnych dostawców.
Adres e-mail i hasło
W sekcji Bezpieczeństwo > Uwierzytelnianie > Metoda logowania w Firebasekonsoli włącz dostawcę E-mail/hasło.
Zarejestruj dostawcę w instancji
AuthService:let authService = AuthService() .withEmailSignIn()
Uwierzytelnianie za pomocą linku w e-mailu
Aby używać logowania za pomocą linku w e-mailu bez hasła:
W sekcji Bezpieczeństwo > Uwierzytelnianie > Metoda logowania konsoli Firebase włącz Adres e-mail/hasło, a następnie włącz logowanie za pomocą linku w e-mailu. Pamiętaj, że aby korzystać z logowania za pomocą linku w e-mailu, musisz włączyć logowanie za pomocą adresu e-mail lub hasła.
Dodaj domenę linku do Autoryzowanych domen.
Skonfiguruj
ActionCodeSettings, przekaż go doAuthConfigurationi zarejestruj dostawcę: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()W tym samym
AppDelegate, w którym wywołujeszFirebaseApp.configure(), dodaj logikę do metodyapplication(_:open:options:), która zwracatrue, gdy otwarty adres URL jest linkiem logowania Firebase Authentication. Ta logika wskazuje, że link został obsłużony przez FirebaseUI i nie powinien być przetwarzany przez inne moduły obsługi linków.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 } }Jeśli tworzysz widoki niestandardowe, wywołaj funkcję
authService.handleSignInLink(url:), gdy link otworzy Twoją aplikację.
Apple
Aby użyć funkcji Zaloguj się przez Apple:
Skonfiguruj logowanie się przez Apple:
- Włącz logowanie się przez Apple w przypadku swojej aplikacji na stronie Certificates, Identifiers & Profiles (Certyfikaty, identyfikatory i profile) w witrynie dla deweloperów Apple.
- Powiąż swoją witrynę z aplikacją zgodnie z opisem w pierwszej sekcji artykułu Konfigurowanie logowania za pomocą Apple w internecie. Gdy pojawi się odpowiedni komunikat, zarejestruj poniższy adres URL jako powrotny adres URL:
Identyfikator projektu Firebase znajdziesz na Firebasestronie ustawień konsoli. Gdy skończysz, zanotuj nowy identyfikator usługi, który będzie potrzebny w następnej sekcji.https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/__/auth/handler
- Utwórz klucz prywatny do logowania się przez Apple. W następnej sekcji będziesz potrzebować nowego klucza prywatnego i identyfikatora klucza.
- Jeśli korzystasz z funkcji usługi Firebase Authentication, które wysyłają e-maile do użytkowników, w tym logowania za pomocą linku w e-mailu, weryfikacji adresu e-mail, cofania zmian na koncie itp., skonfiguruj usługę prywatnego przekaźnika poczty e-mail Apple i zarejestruj
noreply@YOUR_FIREBASE_PROJECT_ID.firebaseapp.com(lub dostosowaną domenę szablonu e-maila), aby Apple mogło przekazywać e-maile wysyłane przez Firebase Authentication na anonimowe adresy e-mail Apple.
W sekcji Bezpieczeństwo > Uwierzytelnianie > Metoda logowania konsoli Firebase włącz Apple.
- Określ identyfikator usługi utworzony w poprzedniej sekcji.
- W sekcji konfiguracji procesu OAuth podaj identyfikator zespołu Apple, klucz prywatny i identyfikator klucza utworzone w poprzedniej sekcji.
W Xcode otwórz sekcję Signing & Capabilities w edytorze projektu i dodaj funkcję Sign in with Apple.
Zarejestruj dostawcę w instancji
AuthService:let authService = AuthService() .withAppleSignIn()
Aby korzystać z logowania przez Google:
W sekcji Bezpieczeństwo > Uwierzytelnianie > Metoda logowania w konsoli Firebase włącz dostawcę Google.
Pobierz nową kopię pliku
GoogleService-Info.plistprojektu i skopiuj ją do projektu Xcode. zastąpić wszystkie dotychczasowe wersje nową wersją;Dodaj niestandardowe schematy URL do projektu w Xcode:
Otwórz konfigurację projektu: w widoku drzewa po lewej stronie kliknij nazwę projektu. W sekcji MIEJSCA DOCELOWE wybierz aplikację, a następnie kliknij kartę Informacje i rozwiń sekcję Typy adresów URL.
Kliknij przycisk + i dodaj schemat adresu URL dla odwróconego identyfikatora klienta. Aby znaleźć tę wartość, otwórz plik konfiguracyjny
i poszukaj kluczaGoogleService-Info.plist REVERSED_CLIENT_ID. Skopiuj wartość tego klucza i wklej ją w polu Schematy URL na stronie konfiguracji. Pozostałe pola pozostaw bez zmian.Po zakończeniu konfiguracja powinna wyglądać podobnie do tej poniżej (ale z wartościami specyficznymi dla Twojej aplikacji):

Zarejestruj dostawcę w instancji
AuthService:let authService = AuthService() .withGoogleSignIn()
Aby użyć logowania przez Facebooka:
Skonfiguruj pakiet SDK Logowanie przez Facebooka na iOS, postępując zgodnie z instrukcjami w witrynie Meta for Developers. Pomiń ostatni krok „Dodaj logowanie przez Facebooka do kodu”.
W sekcji Bezpieczeństwo > Uwierzytelnianie > Metoda logowania w konsoli Firebase włącz dostawcę Facebook. Będziesz potrzebować identyfikatora aplikacji Facebooka i klucza tajnego aplikacji ze strony Meta for Developers.
Zarejestruj dostawcę w instancji
AuthService:let authService = AuthService() .withFacebookSignIn()
Numer telefonu
Aby użyć uwierzytelniania za pomocą telefonu:
W sekcji Bezpieczeństwo > Uwierzytelnianie > Metoda logowania w konsoli Firebase włącz dostawcę Telefon.
Skonfiguruj APNs dla swojej aplikacji zgodnie z instrukcjami w sekcji Rozpoczęcie otrzymywania cichych powiadomień.
Dodaj niestandardowe schematy URL do projektu w Xcode:
Otwórz konfigurację projektu: w widoku drzewa po lewej stronie kliknij nazwę projektu. W sekcji MIEJSCA DOCELOWE wybierz aplikację, a następnie kliknij kartę Informacje i rozwiń sekcję Typy adresów URL.
Kliknij przycisk + i dodaj zakodowany identyfikator aplikacji jako schemat adresu URL. Aby znaleźć tę wartość, otwórz Ustawienia > Ogólne w konsoli Firebase.
Po zakończeniu konfiguracja powinna wyglądać podobnie do tej poniżej (ale z wartościami specyficznymi dla Twojej aplikacji):

W tym samym
AppDelegate, w którym wywołujeszFirebaseApp.configure(), dodaj obsługę tokenów APNs: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 } }Zarejestruj dostawcę w instancji
AuthService:let authService = AuthService() .withPhoneSignIn()
Twitter (X)
Aby użyć logowania przez Twittera:
Wygeneruj dane logowania do interfejsu X API, postępując zgodnie z instrukcjami na stronie X Developers.
W sekcji Bezpieczeństwo > Uwierzytelnianie > Metoda logowania w Firebasekonsoli włącz dostawcę Twitter. Będziesz potrzebować klucza interfejsu API i tajnego klucza API z konsoli X Developer.
Zarejestruj dostawcę w instancji
AuthService:let authService = AuthService() .withTwitterSignIn()
Standardowi dostawcy OAuth2 i OIDC
FirebaseUI obsługuje też wbudowanych dostawców OAuth, takich jak GitHub, Microsoft i Yahoo, a także niestandardowych dostawców OIDC skonfigurowanych w usłudze Uwierzytelnianie Firebase.
let authService = AuthService()
.withOAuthSignIn(OAuthProviderSwift.github())
.withOAuthSignIn(OAuthProviderSwift.microsoft())
.withOAuthSignIn(OAuthProviderSwift.yahoo())
W przypadku niestandardowych dostawców OIDC najpierw skonfiguruj dostawcę w usłudze Firebase Authentication, a potem utwórz element OAuthProviderSwift z identyfikatorem dostawcy i konfiguracją przycisku:
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)
Korzystanie z gotowego widoku uwierzytelniania
FirebaseUI dla SwiftUI udostępnia AuthPickerView, czyli gotowy interfejs uwierzytelniania, który obsługuje cały proces uwierzytelniania. Jest to najprostszy sposób dodania uwierzytelniania do aplikacji.
Przykład
Oto przykład użycia właściwości AuthPickerView z wieloma dostawcami i opcjami konfiguracji:
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)
}
}
}
}
Typowe dostosowywanie
Chociaż wszystkie parametry AuthConfiguration są opcjonalne, większość aplikacji dostosowuje co najmniej te ustawienia:
let configuration = AuthConfiguration(
logo: ImageResource.exampleLogoAsset,
customStringsBundle: .main,
tosUrl: URL(string: "https://example.com/tos"),
privacyPolicyUrl: URL(string: "https://example.com/privacy"),
)
logo: obraz logo wyświetlany w arkuszu uwierzytelniania. Informacje o dodawaniu własnych plików z obrazami znajdziesz w artykule Dodawanie obrazów do projektu Xcode.customStringsBundle: używaj ciągów niestandardowych z określonego pakietu. Jest on używany do lokalizacji, ale także do dostosowywania domyślnych ciągów tekstowych używanych przezAuthPickerView. Aby na przykład ustawić wiadomość wyświetlaną u góry arkusza uwierzytelniania, utwórz plikLocalizable.stringsz tą zawartością:"Sign in with Firebase" = "Sign in to use ExampleApp";
Co zawiera gotowy widok
Gdy używasz AuthPickerView, otrzymujesz:
- Prezentacja arkusza: interfejs uwierzytelniania wyświetla się jako arkusz modalny.
- Wbudowana nawigacja: automatyczne przechodzenie między ekranami logowania, odzyskiwania hasła, uwierzytelniania dwuskładnikowego, linku w e-mailu i weryfikacji telefonicznej.
- Zarządzanie stanem uwierzytelniania: automatyczne przełączanie między interfejsem uwierzytelniania a treściami na podstawie
authService.authenticationState - Kontrola za pomocą
isPresented: możesz kontrolować, kiedy ma się pojawiać arkusz autoryzacji, ustawiającauthService.isPresented = true/false.
Zachowania oparte na opiniach
Domyślny AuthPickerView ma określone zdanie na temat tego, jak obsługiwać kilka złożonych scenariuszy:
1. Rozwiązywanie konfliktów dotyczących kont
Gdy wystąpi konflikt kont (np. logowanie się za pomocą danych logowania, które są już połączone z innym kontem), AuthPickerView automatycznie go rozwiąże:
- Konflikty podczas anonimowego uaktualniania: jeśli funkcja
shouldAutoUpgradeAnonymousUsersjest włączona i podczas anonimowego uaktualniania wystąpi konflikt, system automatycznie wyloguje anonimowego użytkownika i zaloguje go przy użyciu nowych danych logowania. - Inne konflikty: w przypadku konfliktów danych logowania między kontami nieanonimowymi system przechowuje oczekujące dane logowania i próbuje je połączyć po pomyślnym zalogowaniu.
Zajmuje się tym AccountConflictModifier zastosowany na poziomie NavigationStack.
2. Uwierzytelnianie wielopoziomowe (MFA)
Gdy w konfiguracji jest włączone uwierzytelnianie wieloskładnikowe:
- Automatyczne wykrywanie, kiedy podczas logowania wymagane jest uwierzytelnianie wieloskładnikowe
- Wyświetla odpowiednie ekrany uwierzytelniania wieloskładnikowego (SMS lub TOTP).
- Obsługuje procesy rejestracji i zarządzania MFA.
- Obsługuje zarówno czynniki oparte na SMS-ach, jak i hasła jednorazowe generowane na podstawie czasu (TOTP).
3. Obsługa błędów
Widoki domyślne obejmują wbudowaną obsługę błędów:
- Wyświetla przyjazne dla użytkownika komunikaty o błędach w oknach alertów.
- Automatycznie odfiltrowuje błędy obsługiwane wewnętrznie (np.błędy anulowania, automatycznie obsługiwane konflikty).
- Korzystanie z zlokalizowanych komunikatów o błędach za pomocą
StringUtils - Błędy są propagowane za pomocą klucza środowiska
reportError.
4. Logowanie za pomocą linku w e-mailu
Gdy logowanie za pomocą linku w e-mailu jest skonfigurowane:
- Automatyczne zapisywanie adresu e-mail w pamięci aplikacji
- Obsługuje nawigację za pomocą precyzyjnych linków z e-maili.
- zarządza całym procesem weryfikacji adresu e-mail,
- Obsługa przejścia na wyższą wersję przez anonimowych użytkowników za pomocą linku w e-mailu
5. Automatyczne przekształcanie użytkowników anonimowych
Gdy shouldAutoUpgradeAnonymousUsers jest włączona:
- Automatycznie próbuje połączyć anonimowe konta z nowymi danymi logowania.
- Zachowuje dane użytkownika, uaktualniając sesje anonimowe zamiast je zastępować.
- Łatwe rozwiązywanie konfliktów podczas uaktualniania
6. Ponowne uwierzytelnianie w widokach domyślnych
Operacje związane z poufnymi danymi, takie jak usuwanie kont, aktualizowanie haseł czy wyrejestrowywanie etapów uwierzytelniania dwuskładnikowego, wymagają niedawnego uwierzytelnienia. W przypadku korzystania z widoków domyślnych ponowne uwierzytelnianie jest obsługiwane automatycznie na podstawie dostawcy logowania użytkownika.
Gdy operacja związana z poufnymi danymi wymaga ponownego uwierzytelnienia, domyślne widoki automatycznie:
Dostawcy OAuth (Google, Apple, Facebook, Twitter itp.): Wyświetl alert z prośbą o potwierdzenie, a następnie automatycznie uzyskaj nowe dane logowania i dokończ operację.
Adres e-mail/hasło: wyświetla arkusz z prośbą o wpisanie hasła przed kontynuowaniem.
Link w e-mailu: wyświetl alert z prośbą o wysłanie e-maila weryfikacyjnego, a następnie wyświetl arkusz z instrukcjami dotyczącymi sprawdzania poczty. Użytkownik klika link w e-mailu, aby ponownie się uwierzytelnić.
Telefon: wyświetl alert z informacją, że wymagana jest weryfikacja, a następnie wyświetl arkusz weryfikacji kodu SMS.
Po pomyślnej ponownej autoryzacji operacja zostanie automatycznie ponowiona. Podczas korzystania z AuthPickerView lub wbudowanych widoków zarządzania kontem (UpdatePasswordView, SignedInView itp.) nie jest wymagany żaden dodatkowy kod.
Zaawansowane: tworzenie niestandardowych widoków uwierzytelniania
Jeśli potrzebujesz większej kontroli nad interfejsem lub przepływem nawigacji, możesz utworzyć własne niestandardowe widoki uwierzytelniania, nadal korzystając z AuthService w przypadku logiki uwierzytelniania.
Możesz na wiele sposobów łączyć elementy FirebaseUI z logiką niestandardową. W kolejnych sekcjach znajdziesz przykłady niektórych metod dostosowywania, których możesz użyć.
Metoda 1. Niestandardowe przyciski z registerProvider()
Aby mieć pełną kontrolę nad wyglądem przycisku, możesz utworzyć własną implementację AuthProviderUI, która będzie obejmować dowolnego dostawcę i zwracać niestandardowy widok przycisku.
Tworzenie niestandardowego interfejsu dostawcy
Oto przykład tworzenia niestandardowego przycisku Twittera:
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")
}
}
}
}
}
Uproszczony przykład przycisku niestandardowego
Możesz też utworzyć prostsze przyciski niestandardowe dla dowolnego dostawcy:
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)
}
}
Ta metoda działa w przypadku wszystkich dostawców: Google, Apple, Twitter, Facebook, telefon i dostawców OAuth. Wystarczy utworzyć widok przycisku niestandardowego i umieścić go w klasie zgodnej z protokołem AuthProviderUI.
Podejście 2. Domyślne przyciski z niestandardowymi widokami
Możesz użyć AuthService.renderButtons() i pominąć AuthPickerView, aby renderować domyślne przyciski uwierzytelniania, a jednocześnie udostępniać własny układ i nawigację:
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)
}
}
Podejście 3. Widoki niestandardowe z nawigacją niestandardową
Aby mieć pełną kontrolę nad całym procesem, możesz pominąć AuthPickerView i utworzyć własny system nawigacji:
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)
}
}
}
Ważne uwagi dotyczące widoków niestandardowych
Podczas tworzenia widoków niestandardowych musisz samodzielnie wykonać kilka czynności, które AuthPickerView wykonuje automatycznie:
- Konflikty dotyczące kont: wdróż własną strategię rozwiązywania konfliktów za pomocą
AuthServiceError.accountConflict. - Obsługa MFA: zaznacz
SignInOutcomew przypadku.mfaRequiredi ręcznie rozwiąż problem z MFA. - Uaktualnienia użytkowników anonimowych: obsługa łączenia kont anonimowych, jeśli włączona jest funkcja
shouldAutoUpgradeAnonymousUsers. - Stan nawigacji: zarządzanie nawigacją między różnymi ekranami uwierzytelniania (weryfikacja telefonu, odzyskiwanie hasła itp.).
- Stany wczytywania: podczas asynchronicznych operacji uwierzytelniania wyświetlaj wskaźniki wczytywania, obserwując
authService.authenticationState. - Ponowne uwierzytelnianie: obsługa błędów ponownego uwierzytelniania w przypadku operacji związanych z danymi poufnymi (więcej informacji znajdziesz w sekcji Ponowne uwierzytelnianie w widokach niestandardowych poniżej).
Ponowne uwierzytelnianie w widokach niestandardowych
Podczas tworzenia widoków niestandardowych obsługuj ponowne uwierzytelnianie, przechwytując określone błędy i wdrażając własny proces. Operacje wymagające potwierdzenia tożsamości mogą zwracać 4 rodzaje błędów ponownego uwierzytelniania, z których każdy zawiera informacje kontekstowe.
Wzorce implementacji
Dostawcy OAuth (Google, Apple, Facebook, Twitter itp.):
Wyłap błąd i wywołaj funkcję reauthenticate(context:), która automatycznie obsługuje proces 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
}
}
Adres e-mail lub hasło:
Wyłap błąd, poproś o hasło, utwórz dane logowania i wywołaj funkcję 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
}
}
Telefon:
Wyłap błąd, zweryfikuj telefon, utwórz dane logowania i wywołaj funkcję 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
}
}
Link do e-maila:
Wyłap błąd, wyślij e-maila weryfikacyjnego i obsłuż przychodzący adres URL:
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
}
}
Wszystkie obiekty kontekstu ponownego uwierzytelniania zawierają właściwość .displayMessage z tekstem widocznym dla użytkownika.
Niestandardowi dostawcy OAuth
Możesz tworzyć niestandardowych dostawców OAuth dla usług innych niż wbudowane:
⚠️ Ważne: dostawców OIDC (OpenID Connect) trzeba skonfigurować w ustawieniach uwierzytelniania projektu Firebase, zanim będzie można ich używać. W konsoli Firebase kliknij Uwierzytelnianie → Metoda logowania i dodaj dostawcę OIDC z wymaganymi danymi logowania (identyfikator klienta, tajny klucz klienta, URL wystawcy). Musisz też zarejestrować identyfikator URI przekierowania OAuth podany przez Firebase w konsoli dewelopera dostawcy. Szczegółowe instrukcje konfiguracji znajdziesz w dokumentacji Firebase OIDC.
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)
}
}