FirebaseUI ile iOS uygulamanıza oturum açma özelliği ekleme

SwiftUI için FirebaseUI, Firebase Authentication üzerine kurulu, modern ve SwiftUI öncelikli bir kitaplıktır. Bu kitaplık, uygulamanıza önceden oluşturulmuş oturum açma akışları sağlar.

SwiftUI için FirebaseUI'nin aşağıdaki avantajları vardır:

  • Fikre dayalı varsayılan kullanıcı arayüzü: AuthPickerView ile tam bir oturum açma akışı ekleyin.
  • Özelleştirilebilir: Varsayılan düğmeleri kendi düzeninizde oluşturun veya tamamen özel bir deneyim oluşturun.
  • Anonim hesap bağlama: Anonim kullanıcıları isteğe bağlı olarak değiştirmek yerine yükseltin.
  • Hesap yönetimi: Kaydolma, şifre kurtarma ve hesap yönetimi için yerleşik akışlar.
  • Birden fazla sağlayıcı: E-posta/şifre, e-posta bağlantısı, telefonla kimlik doğrulama, Apple, Google, Facebook, Twitter ve standart OAuth2/OIDC sağlayıcılar.
  • Modern kimlik doğrulama özellikleri: Çok öğeli kimlik doğrulaması (MFA) ve async/await API'leri için yerleşik destek.

Başlamadan önce

  • Firebase'i Apple projenize ekleyin. SwiftUI adımlarını tamamladığınızdan emin olun.

  • Uygulamanızın iOS 17 veya sonraki bir sürümü hedeflediğinden emin olun.

Kurulum

SwiftUI için FirebaseUI, Swift paketi olarak sağlanır. Paketi Xcode projenize yüklemek için şunları yapın:

  1. Xcode'da File > Add Package Dependencies'i (Dosya > Paket Bağımlılıkları Ekle) tıklayın.

  2. Paket URL'sini girin:

    https://github.com/firebase/FirebaseUI-iOS
    
  3. Bağımlılık Kuralı menüsünde Bir Sonraki Ana Sürüme Kadar'ı seçin ve minimum sürümü en son yayınlanan sürüm olarak ayarlayın.

  4. Paket Ekle'yi tıklayın, ardından projenize eklemek istediğiniz kitaplıkları seçin.

    Aşağıdaki kitaplık her zaman gereklidir. Temel bağımlılıkların yanı sıra e-posta/şifre ile oturum açma ve e-posta bağlantısıyla oturum açma desteği içerir.

    • FirebaseAuthSwiftUI

     Diğer oturum açma yöntemlerini desteklemek istiyorsanız aşağıdaki kitaplıklardan birini veya daha fazlasını da seçin:

    • FirebaseAppleSwiftUI (Apple ile oturum açma)
    • FirebaseGoogleSwiftUI (Google ile oturum açma)
    • FirebaseFacebookSwiftUI (Facebook ile oturum aç)
    • FirebasePhoneAuthSwiftUI (Telefonla kimlik doğrulama)
    • FirebaseTwitterSwiftUI (Twitter ile oturum açma)
    • FirebaseOAuthSwiftUI (GitHub, Microsoft, Yahoo gibi standart OAuth ve OIDC sağlayıcılar)
  5. Seçili kitaplıkları yüklemek için Paket Ekle'yi tıklayın.

  6. FirebaseUI'nın AuthService özelliğini en üst düzey View başlatıcısında yapılandırın ve hizmeti ortamı kullanarak alt görünümlere iletin.

    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)
      }
    }
    

Oturum açma yöntemlerini ayarlama

Desteklenen her oturum açma yöntemi için bazı ek kurulum adımları gerekir. Aşağıdaki bölümleri genişletin ve tek tek sağlayıcıları ayarlamak için talimatları uygulayın.

E-posta adresi ve şifre

  1. Firebase konsolunun Güvenlik > Kimlik doğrulama > Oturum açma yöntemi bölümünde E-posta/Şifre sağlayıcısını etkinleştirin.

  2. Sağlayıcıyı AuthService örneğinize kaydedin:

    let authService = AuthService()
      .withEmailSignIn()
    

Şifresiz e-posta bağlantısı ile oturum açma özelliğini kullanmak için:

  1. Firebase konsolunun Güvenlik > Kimlik doğrulama > Oturum açma yöntemi bölümünde E-posta/Şifre'yi etkinleştirin, ardından e-posta bağlantısı ile oturum açma özelliğini etkinleştirin. E-posta bağlantısı ile oturum açma özelliğini kullanmak için e-posta veya şifre ile oturum açma özelliğinin etkinleştirilmesi gerektiğini unutmayın.

  2. Bağlantı alanını Yetkili alanlar'a ekleyin.

  3. ActionCodeSettings öğesini yapılandırın, AuthConfiguration öğesine iletin ve sağlayıcıyı kaydedin:

    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()
    
  4. FirebaseApp.configure() işlevini çağırdığınız AppDelegate içinde, açılan URL bir Firebase Authentication oturum açma bağlantısı olduğunda true değerini döndüren application(_:open:options:) yöntemine mantık ekleyin. Bu mantık, bağlantının FirebaseUI tarafından işlendiğini ve diğer bağlantı işleyiciler tarafından işlenmemesi gerektiğini gösterir.

    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
      }
    }
    
  5. Özel görünümler oluşturursanız bağlantı uygulamanızı açtığında authService.handleSignInLink(url:) işlevini çağırın.

Apple

Apple ile oturum açma özelliğini kullanmak için:

  1. Apple ile oturum açma özelliğini yapılandırın:

    1. Apple'ın geliştirici sitesindeki Certificates, Identifiers & Profiles (Sertifikalar, Tanımlayıcılar ve Profiller) sayfasında uygulamanız için Apple ile oturum açma özelliğini etkinleştirin.
    2. Web sitenizi, Web için Apple ile oturum açma özelliğini yapılandırma başlıklı makalenin ilk bölümünde açıklandığı şekilde uygulamanızla ilişkilendirin. İstendiğinde aşağıdaki URL'yi İade URL'si olarak kaydedin:
      https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/__/auth/handler
      Firebase proje kimliğinizi Firebase konsol ayarları sayfasından alabilirsiniz. İşlemi tamamladığınızda yeni hizmet kimliğinizi not edin. Bu kimliğe bir sonraki bölümde ihtiyacınız olacak.
    3. Apple ile Giriş özel anahtarı oluşturun. Bir sonraki bölümde yeni özel anahtarınıza ve anahtar kimliğinize ihtiyacınız olacak.
    4. Firebase Authentication'nın, kullanıcılara e-posta gönderen özelliklerinden (ör. e-posta bağlantısıyla oturum açma, e-posta adresi doğrulama, hesap değişikliği iptali) herhangi birini kullanıyorsanız Apple'ın özel e-posta yönlendirme hizmetini yapılandırın ve noreply@YOUR_FIREBASE_PROJECT_ID.firebaseapp.com'ı (veya özelleştirilmiş e-posta şablonu alanınızı) kaydedin. Böylece Apple, Firebase Authentication tarafından gönderilen e-postaları anonimleştirilmiş Apple e-posta adreslerine yönlendirebilir.
  2. Firebase Konsolu'nun Güvenlik > Kimlik doğrulama > Oturum açma yöntemi bölümünde Apple'ı etkinleştirin.

    • Önceki bölümde oluşturduğunuz hizmet kimliğini belirtin.
    • OAuth kodu akışı yapılandırma bölümünde Apple Team ID'nizi ve önceki bölümde oluşturduğunuz özel anahtarı ve anahtar kimliğini belirtin.
  3. Xcode'da proje düzenleyicisinin Signing & Capabilities (İmzalama ve Yetenekler) bölümünü açın ve Sign in with Apple (Apple ile oturum açma) özelliğini ekleyin.

  4. Sağlayıcıyı AuthService örneğinize kaydedin:

    let authService = AuthService()
      .withAppleSignIn()
    

Google

Google ile oturum açma özelliğini kullanmak için:

  1. Firebase konsolunun Güvenlik > Kimlik doğrulama > Oturum açma yöntemi bölümünde Google sağlayıcısını etkinleştirin.

  2. Projenizin GoogleService-Info.plist dosyasının yeni bir kopyasını indirip Xcode projenize kopyalayın. Mevcut sürümlerin üzerine yeni sürümü yazın.

  3. Xcode projenize özel URL şemaları ekleyin:

    1. Proje yapılandırmanızı açın: Sol ağaç görünümünde proje adını tıklayın. HEDEFLER bölümünden uygulamanızı seçin, ardından Bilgi sekmesini seçin ve URL Türleri bölümünü genişletin.

    2. + düğmesini tıklayın ve tersine çevrilmiş müşteri kimliğiniz için bir URL şeması ekleyin. Bu değeri bulmak için GoogleService-Info.plist yapılandırma dosyasını açın ve REVERSED_CLIENT_ID anahtarını bulun. Bu anahtarın değerini kopyalayıp yapılandırma sayfasındaki URL Şemaları kutusuna yapıştırın. Diğer alanları değiştirmeyin.

      İşlem tamamlandığında yapılandırmanız aşağıdakine benzer bir görünümde olmalıdır (ancak uygulamaya özel değerlerinizle):

  4. Sağlayıcıyı AuthService örneğinize kaydedin:

    let authService = AuthService()
      .withGoogleSignIn()
    

Facebook

Facebook ile Giriş'i kullanmak için:

  1. Meta for Developers sitesindeki talimatları uygulayarak iOS SDK'sı için Facebook ile Giriş'i ayarlayın. Son adım olan "Facebook ile Giriş'i Kodunuza Ekleme" bölümünü atlayın.

  2. Firebase konsolunun Güvenlik > Kimlik doğrulama > Oturum açma yöntemi bölümünde Facebook sağlayıcısını etkinleştirin. Meta for Developers sitesinden Facebook uygulama kimliği ve uygulama gizli anahtarı almanız gerekir.

  3. Sağlayıcıyı AuthService örneğinize kaydedin:

    let authService = AuthService()
     .withFacebookSignIn()
    

Telefon numarası

Telefonla kimlik doğrulamayı kullanmak için:

  1. Firebase konsolunun Güvenlik > Kimlik doğrulama > Oturum açma yöntemi bölümünde Telefon sağlayıcısını etkinleştirin.

  2. Sessiz bildirimler almaya başlama bölümünde belirtildiği şekilde uygulamanız için APN'leri yapılandırın.

  3. Xcode projenize özel URL şemaları ekleyin:

    1. Proje yapılandırmanızı açın: Sol ağaç görünümünde proje adını tıklayın. HEDEFLER bölümünden uygulamanızı seçin, ardından Bilgi sekmesini seçin ve URL Türleri bölümünü genişletin.

    2. + düğmesini tıklayın ve Kodlanmış Uygulama Kimliğinizi URL şeması olarak ekleyin. Bu değeri bulmak için Firebase konsolunda Ayarlar > Genel'i açın.

      İşlem tamamlandığında yapılandırmanız aşağıdakine benzer bir görünümde olmalıdır (ancak uygulamaya özel değerlerinizle):

  4. FirebaseApp.configure()'i çağırdığınız aynı AppDelegate içinde APNs jeton işleyicilerini ekleyin:

    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
      }
    }
    
  5. Sağlayıcıyı AuthService örneğinize kaydedin:

    let authService = AuthService()
      .withPhoneSignIn()
    

Twitter (X)

Twitter ile giriş özelliğini kullanmak için:

  1. X Developers sitesindeki talimatları uygulayarak X API kimlik bilgileri oluşturun.

  2. Firebase konsolunun Güvenlik > Kimlik doğrulama > Oturum açma yöntemi bölümünde Twitter sağlayıcısını etkinleştirin. X Developer Console'dan API anahtarı ve API gizli anahtarı almanız gerekir.

  3. Sağlayıcıyı AuthService örneğinize kaydedin:

    let authService = AuthService()
      .withTwitterSignIn()
    

Standart OAuth2 ve OIDC sağlayıcıları

FirebaseUI, GitHub, Microsoft ve Yahoo gibi yerleşik OAuth sağlayıcılarının yanı sıra Firebase Authentication'da yapılandırılan özel OIDC sağlayıcılarını da destekler.

 let authService = AuthService()
  .withOAuthSignIn(OAuthProviderSwift.github())
  .withOAuthSignIn(OAuthProviderSwift.microsoft())
  .withOAuthSignIn(OAuthProviderSwift.yahoo())

Özel OIDC sağlayıcıları için önce sağlayıcıyı Firebase Authentication'da yapılandırın, ardından sağlayıcı kimliğiniz ve düğme yapılandırmanızla bir OAuthProviderSwift oluşturun:

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)

Hazır kimlik doğrulama görünümünü kullanma

SwiftUI için FirebaseUI, AuthPickerView adlı, önceden oluşturulmuş ve belirli bir görüşe dayalı bir kimlik doğrulama kullanıcı arayüzü sağlar. Bu kullanıcı arayüzü, kimlik doğrulama akışının tamamını sizin için yönetir. Bu, uygulamanıza kimlik doğrulama eklemenin en kolay yoludur.

Örnek

Birden fazla sağlayıcı ve yapılandırma seçeneğiyle kullanılan AuthPickerView örneğini aşağıda bulabilirsiniz:

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)
      }
    }
  }
}

Tipik özelleştirme

Tüm AuthConfiguration parametreleri isteğe bağlı olsa da çoğu uygulama en azından aşağıdaki ayarları özelleştirir:

let configuration = AuthConfiguration(
    logo: ImageResource.exampleLogoAsset,
    customStringsBundle: .main,
    tosUrl: URL(string: "https://example.com/tos"),
    privacyPolicyUrl: URL(string: "https://example.com/privacy"),
)
  • logo: Kimlik doğrulama sayfasında gösterilen logo resmi. Kendi resim öğenizi ekleme hakkında bilgi edinmek için Xcode projenize resim ekleme başlıklı makaleyi inceleyin.

  • customStringsBundle: Belirtilen paketteki özel dizeleri kullanın. Bu, yerelleştirme için olduğu kadar AuthPickerView tarafından kullanılan varsayılan dizeleri özelleştirmek için de kullanılır. Örneğin, kimlik doğrulama sayfasının üst kısmında gösterilen mesajı ayarlamak için aşağıdaki içeriklerle Localizable.strings oluşturun:

    "Sign in with Firebase" = "Sign in to use ExampleApp";
    

Hazır görünümde neler yer alır?

AuthPickerView kullandığınızda elde edeceğiniz avantajlar:

  1. Sayfa Sunumu: Kimlik doğrulama kullanıcı arayüzü, modal sayfa olarak görünür.
  2. Yerleşik gezinme: Oturum açma, şifre kurtarma, MFA, e-posta bağlantısı ve telefon doğrulama ekranları arasında otomatik gezinme
  3. Kimlik Doğrulama Durumu Yönetimi: authService.authenticationState temelinde kimlik doğrulama kullanıcı arayüzü ile içeriğiniz arasında otomatik olarak geçiş yapar.
  4. isPresented üzerinden kontrol: authService.isPresented = true/false ayarını yaparak yetkilendirme sayfasının ne zaman görüneceğini kontrol edin.

Kendi fikrini dayatan davranışlar

Varsayılan AuthPickerView, çeşitli karmaşık senaryoların nasıl ele alınacağı konusunda belirli bir yaklaşımı benimser:

1. Hesap çakışması çözümü

Hesap çakışması (ör. başka bir hesaba zaten bağlı olan bir kimlik bilgisiyle oturum açma) gerçekleştiğinde AuthPickerView bunu otomatik olarak ele alır:

  • Anonim Yükseltme Çakışmaları: shouldAutoUpgradeAnonymousUsers etkinleştirilmişse ve anonim yükseltme sırasında bir çakışma meydana gelirse sistem, anonim kullanıcının oturumunu otomatik olarak kapatır ve yeni kimlik bilgisiyle oturum açar.
  • Diğer Çakışmalar: Anonim olmayan hesaplar arasındaki kimlik bilgisi çakışmalarında sistem, bekleyen kimlik bilgisini saklar ve başarılı bir şekilde oturum açıldıktan sonra bu kimlik bilgisini bağlamaya çalışır.

Bu, NavigationStack düzeyinde uygulanan AccountConflictModifier tarafından işlenir.

2. Çok öğeli kimlik doğrulama (MFA)

Yapılandırmanızda MFA etkinleştirildiğinde:

  • Oturum açma sırasında MFA'nın gerekli olup olmadığını otomatik olarak algılar.
  • Uygun MFA çözünürlük ekranlarını (SMS veya TOTP) gösterir.
  • Çok faktörlü kimlik doğrulama kaydı ve yönetim akışlarını işler.
  • Hem SMS tabanlı hem de zamana dayalı tek kullanımlık şifre (TOTP) faktörlerini destekler.
3. Hata işleme

Varsayılan görünümler, yerleşik hata işlemeyi içerir:

  • Uyarı iletişim kutularında kullanıcı dostu hata mesajları gösterir.
  • Dahili olarak işlenen hataları (ör.iptal hataları, otomatik olarak işlenen çakışmalar) otomatik olarak filtreler.
  • StringUtils üzerinden yerelleştirilmiş hata mesajları kullanır.
  • Hatalar, reportError ortam anahtarı aracılığıyla yayılır.

E-posta bağlantısı ile oturum açma yapılandırıldığında:

  • E-posta adresini uygulama depolama alanında otomatik olarak saklar.
  • E-postadan gelen derin bağlantı gezinmesini işler
  • E-posta doğrulama akışının tamamını yönetir.
  • E-posta bağlantısı üzerinden anonim kullanıcı yükseltmelerini destekler.
5. Anonim kullanıcıların otomatik olarak yükseltilmesi

shouldAutoUpgradeAnonymousUsers etkinleştirildiğinde:

  • Anonim hesapları yeni oturum açma kimlik bilgileriyle otomatik olarak bağlamaya çalışır.
  • Anonim oturumları değiştirmek yerine yükselterek kullanıcı verilerini korur.
  • Yükseltme çakışmalarını sorunsuz bir şekilde yönetir.
6. Varsayılan görünümlerde yeniden kimlik doğrulama

Hesap silme, şifre güncelleme veya MFA faktörlerini kayıttan çıkarma gibi hassas işlemler için yakın zamanda kimlik doğrulama yapılması gerekir. Varsayılan görünümler kullanılırken yeniden kimlik doğrulama, kullanıcının oturum açma sağlayıcısına göre otomatik olarak gerçekleştirilir.

Hassas bir işlem için yeniden kimlik doğrulama gerektiğinde varsayılan görünümler otomatik olarak:

  • OAuth Sağlayıcıları (Google, Apple, Facebook, Twitter vb.): Kullanıcıdan onaylamasını isteyen bir uyarı gösterin, ardından otomatik olarak yeni kimlik bilgileri alın ve işlemi tamamlayın.

  • E-posta/Şifre: Kullanıcıya devam etmeden önce şifresini girmesini isteyen bir sayfa gösterin.

  • E-posta bağlantısı: Doğrulama e-postası göndermeyi isteyen bir uyarı gösterin, ardından e-postayı kontrol etme talimatlarını içeren bir sayfa sunun. Kullanıcı, yeniden kimlik doğrulama işlemini tamamlamak için e-postasındaki bağlantıya dokunur.

  • Telefon: Doğrulama gerektiğini açıklayan bir uyarı gösterin, ardından SMS kodu doğrulama için bir sayfa sunun.

İşlem, yeniden kimlik doğrulama başarılı olduktan sonra otomatik olarak yeniden denenir. AuthPickerView veya yerleşik hesap yönetimi görünümleri (UpdatePasswordView, SignedInView vb.) kullanılırken ek kod gerekmez.

Gelişmiş: Özel Auth görünümleri oluşturma

Kullanıcı arayüzü veya gezinme akışı üzerinde daha fazla kontrole ihtiyacınız varsa kimlik doğrulama mantığı için AuthService'dan yararlanmaya devam ederken kendi özel kimlik doğrulama görünümlerinizi oluşturabilirsiniz.

FirebaseUI öğelerini özel mantıkla birçok şekilde karıştırabilirsiniz. Aşağıdaki bölümlerde, kullanabileceğiniz bazı özelleştirme yaklaşımlarına dair örnekler verilmiştir.

1. yaklaşım: registerProvider() içeren özel düğmeler

Düğme görünümü üzerinde tam kontrol sahibi olmak için herhangi bir sağlayıcıyı sarmalayan ve özel düğme görünümünüzü döndüren kendi özel AuthProviderUI uygulamanızı oluşturabilirsiniz.

Özel sağlayıcı kullanıcı arayüzü oluşturma

Örnek olarak özel bir Twitter düğmesi oluşturma adımları aşağıda verilmiştir:

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")
        }
      }
    }
  }
}

Basitleştirilmiş özel düğme örneği

Ayrıca, herhangi bir sağlayıcı için daha basit özel düğmeler de oluşturabilirsiniz:

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)
  }
}

Bu yaklaşım Google, Apple, Twitter, Facebook, Telefon ve OAuth sağlayıcıları dahil tüm sağlayıcılar için geçerlidir. Özel düğme görünümünüzü oluşturmanız ve AuthProviderUI protokolüne uygun bir sınıfa sarmalamanız yeterlidir.

2. yaklaşım: Özel görünümlere sahip varsayılan düğmeler

Kendi düzeninizi ve gezinmenizi sağlarken varsayılan kimlik doğrulama düğmelerini oluşturmak için AuthService.renderButtons() öğesini kullanabilir ve AuthPickerView öğesini atlayabilirsiniz:

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)
  }
}

3. yaklaşım: Özel gezinme içeren özel görünümler

Akışın tamamı üzerinde tam kontrol sahibi olmak için AuthPickerView simgesini atlayabilir ve kendi gezinme sisteminizi oluşturabilirsiniz:

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)
    }
  }
}

Özel görünümlerle ilgili önemli noktalar

Özel görünümler oluştururken AuthPickerView tarafından otomatik olarak işlenen birkaç şeyi kendiniz yapmanız gerekir:

  1. Hesap çakışmaları: AuthServiceError.accountConflict kullanarak kendi çakışma çözme stratejinizi uygulayın.
  2. ÇOK ÖĞELİ KİMLİK DOĞRULAMA İŞLEME: SignInOutcome için .mfaRequired'ı kontrol edin ve çok öğeli kimlik doğrulama çözümünü manuel olarak gerçekleştirin.
  3. Anonim Kullanıcı Yükseltmeleri: shouldAutoUpgradeAnonymousUsers etkinse anonim hesapların bağlanmasını yönetin
  4. Gezinme Durumu: Farklı kimlik doğrulama ekranları (telefon doğrulama, şifre kurtarma vb.) arasında gezinmeyi yönetin.
  5. Yükleme Durumları: authService.authenticationState gözlemlenerek eş zamansız kimlik doğrulama işlemleri sırasında yükleme göstergeleri gösterilir.
  6. Yeniden kimlik doğrulama: Hassas işlemler için yeniden kimlik doğrulama hatalarını ele alın (aşağıdaki Özel Görünümlerde Yeniden Kimlik Doğrulama bölümüne bakın).

Özel görünümlerde yeniden kimlik doğrulama

Özel görünümler oluştururken belirli hataları yakalayıp kendi akışınızı uygulayarak yeniden kimlik doğrulama işlemini gerçekleştirin. Hassas işlemler, her biri bağlam bilgisi içeren dört tür yeniden kimlik doğrulama hatası verir.

Uygulama kalıpları

OAuth sağlayıcıları (Google, Apple, Facebook, Twitter vb.):

Hatayı yakalayın ve OAuth akışını otomatik olarak işleyen reauthenticate(context:) işlevini çağırın:

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
  }
}

E-posta/Şifre:

Hatayı yakalayın, şifre isteyin, kimlik bilgisi oluşturun ve reauthenticate(with:) işlevini çağırın:

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:

Hatayı yakalayın, telefonu doğrulayın, kimlik bilgisi oluşturun ve reauthenticate(with:)'ı arayın:

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
  }
}

E-posta bağlantısı:

Hatayı yakalayın, doğrulama e-postası gönderin ve gelen URL'yi işleyin:

do {
  try await authService.updatePassword(to: newPassword)
} catch let error as AuthServiceError {
  if case .emailLinkReauthenticationRequired(let context) = error {
    // Send verification email
    try await authService.sendEmailSignInLink(
      email: context.email,
      isReauth: true
    )
    // Show your "Check your email" UI
    await showCheckEmailUI()
    // When user taps the link, it opens your app with a URL
    // Handle it in your URL handler:
    // try await authService.handleSignInLink(url: url)
    // The handleSignInLink method automatically completes reauthentication
    try await authService.updatePassword(to: newPassword) // Retry
  }
}

Tüm yeniden kimlik doğrulama bağlamı nesneleri, kullanıcıya yönelik metin için bir .displayMessage özelliği içerir.

Özel OAuth sağlayıcıları

Yerleşik olanların dışındaki hizmetler için özel OAuth sağlayıcıları oluşturabilirsiniz:

⚠️ Önemli: OIDC (OpenID Connect) sağlayıcıların kullanılabilmesi için Firebase projenizin Kimlik Doğrulama ayarlarında yapılandırılması gerekir. Firebase Console'da Authentication → Sign-in method (Kimlik Doğrulama → Oturum açma yöntemi) bölümüne gidin ve OIDC sağlayıcınızı gerekli kimlik bilgileriyle (istemci kimliği, istemci gizli anahtarı, yayıncı URL'si) ekleyin. Ayrıca, Firebase tarafından sağlanan OAuth yönlendirme URI'sini sağlayıcınızın geliştirici konsoluna kaydetmeniz gerekir. Ayrıntılı kurulum talimatları için Firebase OIDC belgelerine bakın.

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)
  }
}