FirebaseUI per SwiftUI è una libreria moderna, incentrata su SwiftUI, basata su Firebase Authentication che fornisce flussi di accesso predefiniti alla tua app.
FirebaseUI per SwiftUI offre i seguenti vantaggi:
- UI predefinita con opinioni: aggiungi un flusso di accesso completo con
AuthPickerView. - Personalizzabile: esegui il rendering dei pulsanti predefiniti nel tuo layout o crea un'esperienza completamente personalizzata.
- Collegamento di account anonimi: esegui l'upgrade degli utenti anonimi anziché sostituirli.
- Gestione dell'account: flussi integrati per la registrazione, il recupero della password e la gestione dell'account.
- Più provider: email/password, link email, autenticazione tramite numero di telefono, Apple, Google, Facebook, Twitter e provider OAuth2/OIDC standard.
- Funzionalità di autenticazione moderne: supporto integrato per l'autenticazione a più fattori (MFA) e le API async/await.
Prima di iniziare
Aggiungi Firebase al tuo progetto Apple. Assicurati di completare i passaggi di SwiftUI.
Assicurati che la tua app sia destinata a iOS 17 o versioni successive.
Installazione
FirebaseUI per SwiftUI viene fornito come pacchetto Swift. Per installare il pacchetto nel tuo progetto Xcode:
In Xcode, fai clic su File > Add Package Dependencies (File > Aggiungi dipendenze pacchetto).
Inserisci l'URL del pacchetto:
https://github.com/firebase/FirebaseUI-iOSNel menu Regola di dipendenza, seleziona Fino alla versione principale successiva e imposta la versione minima su la release più recente.
Fai clic su Add Package (Aggiungi pacchetto), quindi seleziona le librerie da aggiungere al progetto.
La seguente libreria è sempre obbligatoria. Include le dipendenze principali, nonché il supporto per l'accesso con email e password e l'accesso con link via email.
FirebaseAuthSwiftUI
Se vuoi supportare altri metodi di accesso, seleziona anche una o più delle seguenti librerie:
FirebaseAppleSwiftUI(Accedi con Apple)FirebaseGoogleSwiftUI(Accedi con Google)FirebaseFacebookSwiftUI(Accedi con Facebook)FirebasePhoneAuthSwiftUI(autenticazione telefonica)FirebaseTwitterSwiftUI(Accedi con Twitter)FirebaseOAuthSwiftUI(provider OAuth e OIDC standard come GitHub, Microsoft, Yahoo)
Fai clic su Aggiungi pacchetto per installare le librerie selezionate.
Configura l'oggetto
AuthServicedi FirebaseUI nell'inizializzatore della tuaViewdi primo livello e passa il servizio alle viste secondarie utilizzando l'ambiente.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) } }
Configura i metodi di accesso
Ciascuno dei metodi di accesso supportati richiede alcuni passaggi di configurazione aggiuntivi. Espandi le sezioni di seguito e segui le istruzioni per configurare i singoli provider.
Indirizzo email e password
Dalla sezione Sicurezza > Autenticazione > Metodo di accesso della console Firebase, attiva il provider Email/Password.
Registra il provider nell'istanza
AuthService:let authService = AuthService() .withEmailSignIn()
Autenticazione tramite link via email
Per utilizzare l'accesso senza password con un link via email:
Nella sezione Sicurezza > Autenticazione > Metodo di accesso della console Firebase, attiva Email/Password, quindi attiva l'accesso tramite link via email. Tieni presente che l'accesso con email o password deve essere abilitato per utilizzare l'accesso con link via email.
Aggiungi il dominio del link a Domini autorizzati.
Configura
ActionCodeSettings, passalo aAuthConfiguratione registra il provider: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()Nello stesso
AppDelegatein cui chiamiFirebaseApp.configure(), aggiungi la logica al metodoapplication(_:open:options:)che restituiscetruequando l'URL aperto è un link di accesso Firebase Authentication. Questa logica indica che il link è stato gestito da FirebaseUI e non deve essere elaborato da altri gestori di link.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 } }Se crei visualizzazioni personalizzate, chiama
authService.handleSignInLink(url:)quando il link apre la tua app.
Apple
Per utilizzare Accedi con Apple:
Configura Accedi con Apple:
- Attiva Accedi con Apple per la tua app nella pagina Certificates, Identifiers & Profiles (Certificati, identificatori e profili) del sito per sviluppatori di Apple.
- Associa il tuo sito web alla tua app come descritto nella prima sezione di Configura Accedi con Apple per il web. Quando richiesto, registra il seguente URL come URL di ritorno:
Puoi trovare l'ID progetto Firebase nella pagina delle impostazioni della consoleFirebase. Al termine, prendi nota del nuovo ID servizio, che ti servirà nella sezione successiva.https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/__/auth/handler
- Crea una chiave privata Accedi con Apple. Nella sezione successiva, avrai bisogno della nuova chiave privata e del nuovo ID chiave.
- Se utilizzi una delle funzionalità di Firebase Authentication che inviano email agli utenti, tra cui l'accesso tramite link via email, la verifica dell'indirizzo email, la revoca della modifica dell'account e altre, configura il servizio di inoltro email privato di Apple e registra
noreply@YOUR_FIREBASE_PROJECT_ID.firebaseapp.com(o il dominio del modello di email personalizzato) in modo che Apple possa inoltrare le email inviate da Firebase Authentication agli indirizzi email Apple anonimizzati.
Nella sezione Sicurezza > Autenticazione > Metodo di accesso della console Firebase, attiva Apple.
- Specifica l'ID servizio che hai creato nella sezione precedente.
- Nella sezione di configurazione del flusso di codice OAuth, specifica l'ID del tuo team Apple, la chiave privata e l'ID chiave che hai creato nella sezione precedente.
In Xcode, apri la sezione Signing & Capabilities (Firma e funzionalità) dell'editor del progetto e aggiungi la funzionalità Sign in with Apple (Accedi con Apple).
Registra il provider nell'istanza
AuthService:let authService = AuthService() .withAppleSignIn()
Per utilizzare Accedi con Google:
Nella sezione Sicurezza > Autenticazione > Metodo di accesso della console Firebase, attiva il provider Google.
Scarica una nuova copia del file
GoogleService-Info.plistdel progetto e copiala nel progetto Xcode. Sovrascrivi le versioni esistenti con quella nuova.Aggiungi schemi URL personalizzati al tuo progetto Xcode:
Apri la configurazione del progetto: fai clic sul nome del progetto nella visualizzazione ad albero a sinistra. Seleziona la tua app dalla sezione TARGETS, poi seleziona la scheda Info ed espandi la sezione URL Types.
Fai clic sul pulsante + e aggiungi uno schema URL per l'ID client invertito. Per trovare questo valore, apri il file di configurazione
e cerca la chiaveGoogleService-Info.plist REVERSED_CLIENT_ID. Copia il valore della chiave e incollalo nella casella Schemi URL della pagina di configurazione. Lascia invariati gli altri campi.Al termine, la configurazione dovrebbe essere simile alla seguente (ma con i valori specifici dell'applicazione):
Registra il provider nell'istanza
AuthService:let authService = AuthService() .withGoogleSignIn()
Per utilizzare l'accesso con Facebook:
Configura l'SDK Facebook Login for iOS seguendo le istruzioni sul sito Meta for Developers. Salta il passaggio finale "Aggiungi l'accesso con Facebook al tuo codice".
Nella sezione Sicurezza > Autenticazione > Metodo di accesso della console Firebase, abilita il provider Facebook. Avrai bisogno dell'ID app e del secret dell'app di Facebook dal sito Meta for Developers.
Registra il provider nell'istanza
AuthService:let authService = AuthService() .withFacebookSignIn()
Numero di telefono
Per utilizzare l'autenticazione tramite telefono:
Nella sezione Sicurezza > Autenticazione > Metodo di accesso della console Firebase, attiva il provider Telefono.
Configura gli APN per la tua app come indicato nella sezione Inizia a ricevere notifiche silenziose.
Aggiungi schemi URL personalizzati al tuo progetto Xcode:
Apri la configurazione del progetto: fai clic sul nome del progetto nella visualizzazione ad albero a sinistra. Seleziona la tua app dalla sezione TARGETS, poi seleziona la scheda Info ed espandi la sezione URL Types.
Fai clic sul pulsante + e aggiungi l'ID app codificato come schema URL. Per trovare questo valore, apri Impostazioni > Generali nella console Firebase.
Al termine, la configurazione dovrebbe essere simile alla seguente (ma con i valori specifici dell'applicazione):
Nello stesso
AppDelegatein cui chiamiFirebaseApp.configure(), aggiungi i gestori dei token 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 } }Registra il provider nell'istanza
AuthService:let authService = AuthService() .withPhoneSignIn()
Twitter (X)
Per utilizzare l'accesso con Twitter:
Genera le credenziali API X seguendo le istruzioni sul sito X Developers.
Nella sezione Sicurezza > Autenticazione > Metodo di accesso della console Firebase, attiva il provider Twitter. Avrai bisogno della chiave API e dell'API secret della console per sviluppatori X.
Registra il provider nell'istanza
AuthService:let authService = AuthService() .withTwitterSignIn()
Provider OAuth2 e OIDC standard
FirebaseUI supporta anche provider OAuth integrati come GitHub, Microsoft e Yahoo, nonché provider OIDC personalizzati configurati in Firebase Authentication.
let authService = AuthService()
.withOAuthSignIn(OAuthProviderSwift.github())
.withOAuthSignIn(OAuthProviderSwift.microsoft())
.withOAuthSignIn(OAuthProviderSwift.yahoo())
Per i provider OIDC personalizzati, configura prima il provider in Firebase Authentication, poi crea un OAuthProviderSwift con l'ID provider e la configurazione del pulsante:
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)
Utilizzo della visualizzazione di autenticazione predefinita
FirebaseUI per SwiftUI fornisce AuthPickerView, una UI di autenticazione predefinita e personalizzata che gestisce l'intero flusso di autenticazione per te. Questo è il modo più semplice per aggiungere l'autenticazione alla tua app.
Esempio
Ecco un esempio di AuthPickerView in uso, con più provider e opzioni di configurazione:
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)
}
}
}
}
Personalizzazione tipica
Sebbene tutti i parametri AuthConfiguration siano facoltativi, la maggior parte delle app personalizza almeno le seguenti impostazioni:
let configuration = AuthConfiguration(
logo: ImageResource.exampleLogoAsset,
customStringsBundle: .main,
tosUrl: URL(string: "https://example.com/tos"),
privacyPolicyUrl: URL(string: "https://example.com/privacy"),
)
logo: l'immagine del logo visualizzata nel foglio di autenticazione. Per informazioni su come includere il tuo asset immagine, consulta Aggiungere immagini al progetto Xcode.customStringsBundle: utilizza stringhe personalizzate dal bundle specificato. Questo viene utilizzato per la localizzazione, ma anche per personalizzare le stringhe predefinite utilizzate daAuthPickerView. Ad esempio, per impostare il messaggio visualizzato nella parte superiore del foglio di autenticazione, creaLocalizable.stringscon i seguenti contenuti:"Sign in with Firebase" = "Sign in to use ExampleApp";
Cosa è incluso nella visualizzazione predefinita
Quando utilizzi AuthPickerView, ricevi:
- Sheet Presentation: l'interfaccia utente di autenticazione viene visualizzata come un foglio modale
- Navigazione integrata: navigazione automatica tra le schermate di accesso, recupero della password, MFA, link via email e verifica telefonica.
- Gestione dello stato di autenticazione: passa automaticamente dalla UI di autenticazione ai tuoi contenuti in base a
authService.authenticationState - Controlla tramite
isPresented: controlla quando viene visualizzato il foglio di autenticazione impostandoauthService.isPresented = true/false
Comportamenti predefiniti
Il AuthPickerView predefinito è rigido su come gestire diversi scenari complessi:
1. Risoluzione dei conflitti tra account
Quando si verifica un conflitto tra account (ad es. l'accesso con una credenziale già collegata a un altro account), AuthPickerView lo gestisce automaticamente:
- Conflitti di upgrade anonimo: se
shouldAutoUpgradeAnonymousUsersè abilitato e si verifica un conflitto durante l'upgrade anonimo, il sistema disconnette automaticamente l'utente anonimo e accede con la nuova credenziale. - Altri conflitti: per i conflitti di credenziali tra account non anonimi, il sistema memorizza le credenziali in attesa e tenta di collegarle dopo l'accesso riuscito.
Questo viene gestito da AccountConflictModifier applicato a livello di NavigationStack.
2. Autenticazione a più fattori (MFA)
Quando l'MFA è abilitata nella tua configurazione:
- Rileva automaticamente quando è richiesta l'MFA durante l'accesso
- Presenta le schermate di risoluzione MFA appropriate (SMS o TOTP)
- Gestisce i flussi di registrazione e gestione MFA
- Supporta i fattori di password monouso (TOTP) basati su SMS e su tempo
3. Gestione degli errori
Le visualizzazioni predefinite includono la gestione degli errori integrata:
- Mostra messaggi di errore di facile comprensione nelle finestre di dialogo di avviso
- Filtra automaticamente gli errori gestiti internamente (ad es. errori di annullamento, conflitti gestiti automaticamente)
- Utilizza messaggi di errore localizzati tramite
StringUtils - Gli errori vengono propagati tramite la chiave di ambiente
reportError
4. Accesso tramite link via email
Quando l'accesso tramite link via email è configurato:
- Memorizza automaticamente l'indirizzo email nello spazio di archiviazione dell'app
- Gestisce la navigazione tramite deep link dall'email
- Gestisce l'intero flusso di verifica email
- Supporta gli upgrade degli utenti anonimi tramite link via email
5. Upgrade automatico degli utenti anonimi
Quando shouldAutoUpgradeAnonymousUsers è abilitata:
- Tenta automaticamente di collegare gli account anonimi alle nuove credenziali di accesso
- Conserva i dati utente eseguendo l'upgrade anziché sostituire le sessioni anonime
- Gestisce i conflitti di upgrade in modo controllato
6. Riautenticazione nelle visualizzazioni predefinite
Le operazioni sensibili, come l'eliminazione di account, l'aggiornamento delle password o l'annullamento della registrazione dei fattori MFA, richiedono un'autenticazione recente. Quando utilizzi le visualizzazioni predefinite, la riautenticazione viene gestita automaticamente in base al provider di accesso dell'utente.
Quando un'operazione sensibile richiede la riautenticazione, le visualizzazioni predefinite automaticamente:
Provider OAuth (Google, Apple, Facebook, Twitter e così via): Visualizza un avviso che chiede all'utente di confermare, quindi ottieni automaticamente nuove credenziali e completa l'operazione.
Email/Password: mostra un foglio che chiede all'utente di inserire la password prima di continuare.
Link email: mostra un avviso che chiede di inviare un'email di verifica, quindi presenta un foglio con le istruzioni per controllare l'email. L'utente tocca il link nell'email per completare la riautenticazione.
Telefono: mostra un avviso che spiega che è necessaria la verifica, quindi un foglio per la verifica del codice SMS.
L'operazione viene ritentata automaticamente dopo la riautenticazione. Non è necessario alcun codice aggiuntivo quando utilizzi AuthPickerView o le visualizzazioni di gestione dell'account integrate (UpdatePasswordView, SignedInView e così via).
Avanzato: creazione di visualizzazioni di autenticazione personalizzate
Se hai bisogno di un maggiore controllo sulla UI o sul flusso di navigazione, puoi creare le tue visualizzazioni di autenticazione personalizzate, sfruttando comunque AuthService per la logica di autenticazione.
Puoi combinare elementi di FirebaseUI con la logica personalizzata in molti modi. Le sezioni seguenti contengono esempi di alcuni degli approcci di personalizzazione che potresti utilizzare.
Approccio 1: pulsanti personalizzati con registerProvider()
Per un controllo completo sull'aspetto dei pulsanti, puoi creare un'implementazione AuthProviderUI personalizzata che aggrega qualsiasi provider e restituisce la visualizzazione dei pulsanti personalizzata.
Creazione di una UI del provider personalizzata
Ecco un esempio di come creare un pulsante Twitter personalizzato:
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")
}
}
}
}
}
Esempio di pulsante personalizzato semplificato
Puoi anche creare pulsanti personalizzati più semplici per qualsiasi provider:
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)
}
}
Questo approccio funziona per tutti i provider: Google, Apple, Twitter, Facebook, telefono e provider OAuth. Crea semplicemente la tua visualizzazione dei pulsanti personalizzata e inseriscila in una classe conforme a AuthProviderUI.
Approccio 2: pulsanti predefiniti con visualizzazioni personalizzate
Puoi utilizzare AuthService.renderButtons() e bypassare AuthPickerView per eseguire il rendering dei pulsanti di autenticazione predefiniti, fornendo al contempo il tuo layout e la tua navigazione:
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)
}
}
Approccio 3: visualizzazioni personalizzate con navigazione personalizzata
Per un controllo completo sull'intero flusso, puoi bypassare AuthPickerView e creare il tuo sistema di navigazione:
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)
}
}
}
Considerazioni importanti per le visualizzazioni personalizzate
Quando crei visualizzazioni personalizzate, devi gestire autonomamente diversi aspetti che AuthPickerView gestisce automaticamente:
- Conflitti tra account: implementa la tua strategia di risoluzione dei conflitti utilizzando
AuthServiceError.accountConflict - Gestione dell'MFA: controlla
SignInOutcomeper.mfaRequirede gestisci manualmente la risoluzione dell'MFA - Upgrade degli utenti anonimi: gestisci il collegamento degli account anonimi se
shouldAutoUpgradeAnonymousUsersè abilitato - Stato di navigazione: gestisci la navigazione tra le diverse schermate di autenticazione (verifica telefonica, recupero della password e così via).
- Stati di caricamento: mostra gli indicatori di caricamento durante le operazioni di autenticazione asincrona osservando
authService.authenticationState - Riautenticazione: gestisci gli errori di riautenticazione per le operazioni sensibili (consulta la sezione Riautenticazione nelle visualizzazioni personalizzate di seguito)
Riautenticazione nelle visualizzazioni personalizzate
Quando crei visualizzazioni personalizzate, gestisci la riautenticazione rilevando errori specifici e implementando il tuo flusso. Le operazioni sensibili generano quattro tipi di errori di riautenticazione, ciascuno contenente informazioni sul contesto.
Pattern di implementazione
Provider OAuth (Google, Apple, Facebook, Twitter e così via):
Intercetta l'errore e chiama reauthenticate(context:), che gestisce automaticamente il flusso 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:
Intercetta l'errore, chiedi la password, crea la credenziale e chiama 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
}
}
Telefono:
Rileva l'errore, verifica il numero di telefono, crea la credenziale e chiama 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:
Rileva l'errore, invia l'email di verifica e gestisci l'URL in entrata:
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
}
}
Tutti gli oggetti del contesto di riautenticazione includono una proprietà .displayMessage per il testo rivolto agli utenti.
Provider OAuth personalizzati
Puoi creare provider OAuth personalizzati per servizi diversi da quelli integrati:
⚠️ Importante: i provider OIDC (OpenID Connect) devono essere configurati nelle impostazioni di autenticazione del progetto Firebase prima di poter essere utilizzati. Nella console Firebase, vai ad Authentication → Sign-in method (Autenticazione → Metodo di accesso) e aggiungi il tuo provider OIDC con le credenziali richieste (ID client, client secret, URL emittente). Devi anche registrare l'URI di reindirizzamento OAuth fornito da Firebase nella console per sviluppatori del tuo provider. Per istruzioni dettagliate sulla configurazione, consulta la documentazione di 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)
}
}