
FirebaseUI dla SwiftUI to nowoczesna biblioteka oparta na Firebase Authentication, która udostępnia gotowe procesy logowania w aplikacji.
FirebaseUI dla SwiftUI ma te zalety:
- Domyślny interfejs użytkownika: dodaj kompletny proces logowania za pomocą
AuthPickerView. - Możliwość dostosowania: możesz renderować domyślne przyciski we własnym układzie lub utworzyć w pełni niestandardowe środowisko.
- Anonimowe łączenie kont: opcjonalnie możesz uaktualnić konta użytkowników anonimowych zamiast je zastępować.
- Zarządzanie kontem: wbudowane procesy rejestracji, odzyskiwania hasła i zarządzania kontem.
- Wielu dostawców: adres e-mail i hasło, link do adresu e-mail, uwierzytelnianie przez telefon, Apple, Google, Facebook, Twitter oraz 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. Pamiętaj, aby wykonać kroki dotyczące SwiftUI.
Upewnij się, że aplikacja jest przeznaczona na system iOS 17 lub nowszy.
Instalacja
FirebaseUI dla SwiftUI jest dostarczany 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 Dependency Rule (Reguła zależności) wybierz Up to Next Major Version (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.
Zawsze wymagana jest ta biblioteka: Zawiera podstawowe zależności, a także obsługę logowania się za pomocą adresu e-mail i hasła oraz linku e-mail.
FirebaseAuthSwiftUI
Jeśli chcesz obsługiwać inne metody logowania, wybierz też co najmniej 1 z tych bibliotek:
FirebaseAppleSwiftUI(Zaloguj się przez Apple)FirebaseGoogleSwiftUI(Zaloguj się przez Google)FirebaseFacebookSwiftUI(Zaloguj się przez Facebooka)FirebasePhoneAuthSwiftUI(uwierzytelnianie przez telefon)FirebaseTwitterSwiftUI(Zaloguj się przez Twittera)FirebaseOAuthSwiftUI(standardowi dostawcy OAuth i OIDC, tacy jak GitHub, Microsoft, Yahoo)
Kliknij Add Package (Dodaj pakiet), aby zainstalować wybrane biblioteki.
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 konsoli Firebase 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żyć logowania bez hasła za pomocą linku wysłanego e-mailem:
W sekcji Bezpieczeństwo > Uwierzytelnianie > Metoda logowania konsoli Firebase włącz opcję 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ż 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 obiekcie
AppDelegate, w którym wywołujeszFirebaseApp.configure(), dodaj do metodyapplication(_:open:options:)logikę, 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
authService.handleSignInLink(url:), gdy link otworzy aplikację.
Apple
Aby korzystać z funkcji Zaloguj się przez Apple:
Skonfiguruj funkcję Zaloguj się przez Apple:
- Włącz funkcję Zaloguj się przez Apple w aplikacji na stronie Certificates, Identifiers & Profiles (Certyfikaty, identyfikatory i profile) w witrynie Apple dla deweloperów.
- Powiąż witrynę z aplikacją zgodnie z opisem w pierwszej sekcji artykułu Configure Sign In with Apple for the web (Konfigurowanie funkcji Zaloguj się przez Apple w internecie). Gdy pojawi się prośba, zarejestruj ten adres URL jako adres URL zwrotu:
Identyfikator projektu w Firebase znajdziesz na stronie ustawień konsoli Firebase. Gdy skończysz, zanotuj nowy identyfikator usługi, który będzie Ci potrzebny w następnej sekcji.https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/__/auth/handler
- Utwórz klucz prywatny funkcji Zaloguj się przez Apple. W następnej sekcji będziesz potrzebować nowego klucza prywatnego i identyfikatora klucza.
- Jeśli używasz funkcji 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, unieważnienia zmiany konta i innych, skonfiguruj usługę prywatnego przekazywania poczty e-mail Apple i zarejestruj
noreply@YOUR_FIREBASE_PROJECT_ID.firebaseapp.com(lub domenę niestandardowego szablonu e-maila), aby firma Apple mogła 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.
- Podaj identyfikator usługi utworzony w poprzedniej sekcji.
- W sekcji Konfiguracja procesu kodu OAuth podaj identyfikator zespołu Apple oraz klucz prywatny i identyfikator klucza utworzone w poprzedniej sekcji.
W Xcode otwórz sekcję Signing & Capabilities (Podpisywanie i funkcje) w edytorze projektu i dodaj funkcję Sign in with Apple (Zaloguj się przez Apple).
Zarejestruj dostawcę w instancji
AuthService:let authService = AuthService() .withAppleSignIn()
Aby używać funkcji Logowanie przez Google:
W sekcji Bezpieczeństwo > Uwierzytelnianie > Metoda logowania konsoli Firebase włącz dostawcę Google.
Pobierz nową kopię pliku
GoogleService-Info.plistprojektu i skopiuj ją do projektu Xcode. Zastąp wszystkie istniejące wersje nową.Dodaj niestandardowe schematy URI adresów URL do projektu Xcode:
Otwórz konfigurację projektu: kliknij nazwę projektu w widoku drzewa po lewej stronie. Wybierz aplikację w sekcji TARGETS (Cele), a następnie kliknij kartę Info (Informacje) i rozwiń sekcję URL Types (Typy adresów URL).
Kliknij przycisk + i dodaj schemat URI adresu URL dla odwróconego identyfikatora klienta. Aby znaleźć tę wartość, otwórz plik konfiguracji
i poszukaj kluczaGoogleService-Info.plist REVERSED_CLIENT_ID. Skopiuj wartość tego klucza i wklej ją w polu Schematy adresów URL na stronie konfiguracji. Pozostałe pola pozostaw bez zmian.Po zakończeniu konfiguracja powinna wyglądać podobnie do tej (ale z wartościami specyficznymi dla Twojej aplikacji):

Zarejestruj dostawcę w instancji
AuthService:let authService = AuthService() .withGoogleSignIn()
Aby używać logowania przez Facebooka:
Skonfiguruj pakiet SDK Facebook Login for iOS, postępując zgodnie z instrukcjami na stronie Meta for Developers. Pomiń ostatni krok „Add Facebook Login to Your Code” (Dodaj logowanie przez Facebooka do kodu).
W sekcji Zabezpieczenia > Uwierzytelnianie > Metoda logowania konsoli Firebase włącz dostawcę Facebook. Potrzebne będą identyfikator aplikacji na Facebooku i tajny klucz aplikacji z witryny Meta for Developers.
Zarejestruj dostawcę w instancji
AuthService:let authService = AuthService() .withFacebookSignIn()
Numer telefonu
Aby użyć uwierzytelniania przez telefon:
W sekcji Zabezpieczenia > Uwierzytelnianie > Metoda logowania konsoli Firebase włącz dostawcę Telefon.
Skonfiguruj APN dla aplikacji zgodnie z instrukcjami w sekcji Zacznij otrzymywać ciche powiadomienia.
Dodaj niestandardowe schematy URI adresów URL do projektu Xcode:
Otwórz konfigurację projektu: kliknij nazwę projektu w widoku drzewa po lewej stronie. Wybierz aplikację w sekcji TARGETS (Cele), a następnie kliknij kartę Info (Informacje) i rozwiń sekcję URL Types (Typy adresów URL).
Kliknij przycisk + i dodaj zakodowany identyfikator aplikacji jako schemat URI adresu URL. Aby znaleźć tę wartość, w konsoli Firebase otwórz Ustawienia > Ogólne.
Po zakończeniu konfiguracja powinna wyglądać podobnie do tej (ale z wartościami specyficznymi dla Twojej aplikacji):

W tym samym pliku
AppDelegate, w którym wywołujeszFirebaseApp.configure(), dodaj moduły obsługi tokenów 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 } }Zarejestruj dostawcę w instancji
AuthService:let authService = AuthService() .withPhoneSignIn()
Twitter (X)
Aby użyć logowania przez Twittera:
Wygeneruj dane logowania do interfejsu API X, postępując zgodnie z instrukcjami na stronie X Developers.
W sekcji Bezpieczeństwo > Uwierzytelnianie > Metoda logowania konsoli Firebase włącz dostawcę Twitter. Będziesz potrzebować klucza interfejsu API i tajnego klucza interfejsu 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 Uwierzytelnianiu Firebase.
let authService = AuthService()
.withOAuthSignIn(OAuthProviderSwift.github())
.withOAuthSignIn(OAuthProviderSwift.microsoft())
.withOAuthSignIn(OAuthProviderSwift.yahoo())
W przypadku niestandardowych dostawców OIDC najpierw skonfiguruj dostawcę w Firebase Authentication, a następnie 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, dostosowany interfejs uwierzytelniania, który obsługuje cały proces uwierzytelniania. To najprostszy sposób na dodanie uwierzytelniania do aplikacji.
Przykład
Oto przykład użycia 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 dołączaniu własnego komponentu z obrazem znajdziesz w artykule o dodawaniu obrazów do projektu Xcode.customStringsBundle: użyj niestandardowych ciągów znaków z określonego pakietu. Służy on do lokalizacji, ale też do dostosowywania domyślnych ciągów znaków używanych przezAuthPickerView. Aby na przykład ustawić komunikat wyświetlany u góry arkusza uwierzytelniania, utwórz plikLocalizable.stringso następującej treści:"Sign in with Firebase" = "Sign in to use ExampleApp";
Co zawiera gotowy widok
Gdy używasz AuthPickerView, otrzymujesz:
- Prezentacja arkusza: interfejs uwierzytelniania jest wyświetlany jako arkusz modalny.
- Wbudowana nawigacja: automatyczna nawigacja między ekranami logowania, odzyskiwania hasła, MFA, linku do e-maila i weryfikacji telefonicznej.
- Zarządzanie stanem uwierzytelniania: automatycznie przełącza się między interfejsem uwierzytelniania a treściami na podstawie
authService.authenticationState - Sterowanie za pomocą
isPresented: możesz kontrolować, kiedy pojawia się arkusz uwierzytelniania, ustawiającauthService.isPresented = true/false.
Zachowania oparte na opiniach
Domyślny AuthPickerView ma określone podejście do obsługi kilku 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ązuje:
- Konflikty podczas anonimowego uaktualniania: jeśli opcja
shouldAutoUpgradeAnonymousUsersjest włączona i podczas anonimowego uaktualniania wystąpi konflikt, system automatycznie wyloguje anonimowego użytkownika i zaloguje się 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 udanym zalogowaniu.
Odpowiada za to AccountConflictModifier zastosowany na poziomie NavigationStack.
2. Uwierzytelnianie wielopoziomowe (MFA)
Gdy w konfiguracji jest włączone uwierzytelnianie wieloskładnikowe:
- Automatycznie wykrywa, 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 czynniki SMS-owe 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ć w oknach alertów przyjazne dla użytkownika komunikaty o błędach;
- Automatycznie odfiltrowuje błędy, które są obsługiwane wewnętrznie (np.błędy anulowania, automatycznie obsługiwane konflikty).
- Używa zlokalizowanych komunikatów o błędach w polu
StringUtils - Błędy są propagowane przez klucz środowiska
reportError
4. Logowanie za pomocą linku w e-mailu
Gdy skonfigurowane jest logowanie za pomocą linku e-mail:
- Automatycznie zapisuje adres e-mail w pamięci aplikacji.
- Obsługuje nawigację za pomocą precyzyjnych linków z e-maila.
- Zarządza całym procesem potwierdzania adresu e-mail
- Obsługuje uaktualnienia anonimowych użytkowników za pomocą linku z e-maila.
5. Automatyczne uaktualnianie użytkowników anonimowych
Gdy shouldAutoUpgradeAnonymousUsers jest włączone:
- Automatycznie próbuje połączyć konta anonimowe z nowymi danymi logowania.
- zachowuje dane użytkownika, uaktualniając sesje anonimowe, zamiast je zastępować;
- Prawidłowo obsługuje konflikty uaktualnień.
6. Ponowne uwierzytelnianie w widokach domyślnych
Operacje poufne, takie jak usuwanie kont, aktualizowanie haseł czy wyrejestrowywanie czynników MFA, wymagają niedawnego uwierzytelnienia. W przypadku 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, widoki domyślne 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ę.
E-mail/hasło: wyświetl 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 arkusz z instrukcjami dotyczącymi sprawdzenia poczty e-mail. Użytkownik klika link w e-mailu, aby dokończyć ponowne uwierzytelnianie.
Telefon: wyświetl alert z informacją, że wymagana jest weryfikacja, a następnie arkusz do weryfikacji kodu SMS.
Operacja zostanie automatycznie ponowiona po pomyślnym ponownym uwierzytelnieniu. Jeśli używasz 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 nawigacją, możesz utworzyć własne niestandardowe widoki uwierzytelniania, nadal korzystając z AuthService do obsługi logiki uwierzytelniania.
Elementy FirebaseUI można łączyć z niestandardową logiką na wiele sposobów. W poniższych sekcjach znajdziesz przykłady niektórych metod dostosowywania, których możesz użyć.
Metoda 1. Przyciski niestandardowe z registerProvider()
Aby mieć pełną kontrolę nad wyglądem przycisku, możesz utworzyć własną implementację AuthProviderUI, która opakowuje dowolnego dostawcę i zwraca widok niestandardowego przycisku.
Tworzenie niestandardowego interfejsu dostawcy
Oto przykład, jak utworzyć niestandardowy przycisk 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")
}
}
}
}
}
Przykład uproszczonego 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, Twittera, Facebooka, telefonu i OAuth. Wystarczy utworzyć niestandardowy widok przycisku i umieścić go w klasie zgodnej z AuthProviderUI.
Podejście 2. Przyciski domyślne z widokami niestandardowymi
Możesz użyć AuthService.renderButtons() i pominąć AuthPickerView, aby renderować domyślne przyciski uwierzytelniania, jednocześnie udostępniając 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 niestandardową nawigacją
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 obsłużyć kilka rzeczy, które AuthPickerView obsługuje automatycznie:
- Konflikty dotyczące kont: wdróż własną strategię rozwiązywania konfliktów za pomocą
AuthServiceError.accountConflict. - Obsługa uwierzytelniania wielopoziomowego: sprawdź
SignInOutcomepod kątem.mfaRequiredi ręcznie rozwiąż problem z uwierzytelnianiem wielopoziomowym. - Uaktualnienia anonimowych użytkowników: obsługa łączenia kont anonimowych, jeśli włączona jest funkcja
shouldAutoUpgradeAnonymousUsers - Stan nawigacji: zarządzanie nawigacją między różnymi ekranami uwierzytelniania (weryfikacja telefoniczna, odzyskiwanie hasła itp.).
- Stany wczytywania: wyświetlaj wskaźniki wczytywania podczas asynchronicznych operacji uwierzytelniania, obserwując
authService.authenticationState. - Ponowne uwierzytelnianie: obsługa błędów ponownego uwierzytelniania w przypadku operacji związanych z danymi poufnymi (patrz 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 poufne powodują wystąpienie 4 rodzajów błędów ponownego uwierzytelniania, z których każdy zawiera informacje o kontekście.
Wzorce implementacji
Dostawcy OAuth (Google, Apple, Facebook, Twitter itp.):
Przechwyć 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
}
}
Email/Password:
Przechwyć błąd, poproś o hasło, utwórz dane logowania i wywołaj 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:
Przechwyć błąd, zweryfikuj telefon, utwórz dane logowania i wywołaj 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:
Przechwyć 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 dla tekstu widocznego dla użytkownika.
Niestandardowi dostawcy OAuth
Możesz tworzyć niestandardowych dostawców OAuth dla usług innych niż wbudowane:
⚠️ Ważne: dostawcy OIDC (OpenID Connect) muszą zostać skonfigurowani w ustawieniach uwierzytelniania projektu w Firebase, zanim będzie można ich używać. W konsoli Firebase otwórz Authentication → Sign-in method (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)
}
}