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

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

SwiftUI için FirebaseUI aşağıdaki avantajları sunar:

  • Özelleştirilmiş varsayılan kullanıcı arayüzü: AuthPickerView ile eksiksiz 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: İsteğe bağlı olarak, anonim kullanıcıları 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 eş zamansız/bekleme API'leri için yerleşik destek.

Başlamadan önce

Kurulum

SwiftUI için FirebaseUI, Swift paketi olarak sunulur. Paketi Xcode projenize yüklemek için aşağıdakileri 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. Dependency Rule (Bağımlılık Kuralı) menüsünde Up to Next Major Version'ı (Sonraki Ana Sürüme Kadar) seçin ve minimum sürümü en son sürüm olarak ayarlayın.

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

    Aşağıdaki kitaplık her zaman gereklidir. Bu paket, temel bağımlılıkların yanı sıra e-posta/şifre ve e-posta bağlantısıyla oturum açma desteğini 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çma)
    • 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. Üst düzey View başlatıcınızda FirebaseUI'ın AuthService öğesini yapılandırın ve ortamı kullanarak hizmeti çocuk ekranlarına 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 oturum açma yöntemlerinin her biri için ek kurulum adımları gerekir. Aşağıdaki bölümleri genişletin ve sağlayıcıları ayrı ayrı 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ıyla 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 ve ardından e-posta bağlantısıyla oturum açmayı etkinleştirin. E-posta bağlantısıyla oturum açma özelliğini kullanmak için e-posta veya şifreyle oturum açma özelliğinin etkinleştirilmesi gerektiğini unutmayın.

  2. Bağlantı alan adını Yetkili alan adları'na 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() yöntemini çağırdığınız AppDelegate içinde, açılan URL bir Firebase Authentication oturum açma bağlantısı olduğunda true döndüren mantığı application(_:open:options:) yöntemine 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şturuyorsanız bağlantı uygulamanızı açtığında authService.handleSignInLink(url:) yöntemini çağırın.

Apple

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

  1. Apple ile Oturum Açma özelliğini yapılandırma:

    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 için Apple ile Oturum Açma'yı yapılandırma başlıklı makalenin ilk bölümünde açıklandığı şekilde web sitenizi uygulamanızla ilişkilendirin. İstendiğinde aşağıdaki URL'yi dönüş URL'si olarak kaydedin:
      https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/__/auth/handler
      Firebase proje kimliğinizi Firebase konsol ayarları sayfasında bulabilirsiniz. İşlemi tamamladığınızda yeni hizmet kimliğinizi not edin. Bir sonraki bölümde bu kimliğe ihtiyacınız olacak.
    3. Apple ile Oturum Açma ö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'in 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ğini iptal etme) herhangi birini kullanıyorsanız Apple özel e-posta geçiş 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 iletebilir.
  2. Firebase konsolunun 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ırması bölümünde, Apple Ekip Kimliğinizi ve önceki bölümde oluşturduğunuz özel anahtarı ve anahtar kimliğini belirtin.
  3. Xcode'da proje düzenleyicinin Signing & Capabilities (İmzalama ve Özellikler) 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ı indirin ve 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. TARGETS (HEDEFLER) bölümünden uygulamanızı seçin, ardından Info (Bilgi) sekmesini seçip URL Types (URL Türleri) bölümünü genişletin.

    2. + düğmesini tıklayın ve ters çevrilmiş istemci 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ın ve yapılandırma sayfasındaki URL Şemaları kutusuna yapıştırın. Diğer alanları olduğu gibi bırakın.

      İşlem tamamlandığında yapılandırmanız aşağıdakine benzer bir görünüme sahip olmalıdır (ancak uygulamanıza özgü değerler içermelidir):

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

    let authService = AuthService()
      .withGoogleSignIn()
    

Facebook

Facebook Giriş'i kullanmak için:

  1. Meta for Developers sitesindeki talimatları uygulayarak iOS için Facebook Giriş SDK'sını ayarlayın. "Kodunuza Facebook Girişi Ekleyin" adlı son adımı 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ı 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ündeki talimatları uygulayarak 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. TARGETS (HEDEFLER) bölümünden uygulamanızı seçin, ardından Info (Bilgi) sekmesini seçip URL Types (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üme sahip olmalıdır (ancak uygulamanıza özgü değerler içermelidir):

  4. FirebaseApp.configure() yöntemini çağırdığınız AppDelegate dosyasına APN jeton işleyicileri 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 bilgilerini oluşturun.

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

  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 yanı sıra Firebase Authentication'da yapılandırılmış özel OIDC sağlayıcıları da destekler.

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

Özel OIDC sağlayıcıları için önce Firebase Authentication'da sağlayıcıyı 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)

Önceden oluşturulmuş kimlik doğrulama görünümünü kullanma

SwiftUI için FirebaseUI, tüm kimlik doğrulama akışını sizin için yöneten, önceden oluşturulmuş ve özel olarak tasarlanmış bir kimlik doğrulama kullanıcı arayüzü olan AuthPickerView sağlar. Bu, uygulamanıza kimlik doğrulama eklemenin en kolay yoludur.

Örnek

Birden fazla sağlayıcı ve yapılandırma seçeneğiyle AuthPickerView kullanımına dair bir örneği 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

AuthConfiguration parametrelerinin tümü 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 için Xcode projenize resim ekleme başlıklı makaleyi inceleyin.

  • customStringsBundle: Belirtilen paketteki özel dizeleri kullanın. Bu, yerelleştirme için kullanılır ancak 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 şu içerikle Localizable.strings oluşturun:

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

Önceden oluşturulmuş görünüme neler dahildir?

AuthPickerView kullandığınızda şunları elde edersiniz:

  1. Sayfa sunumu: Kimlik doğrulama kullanıcı arayüzü, kalıcı 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 değerine göre kimlik doğrulama kullanıcı arayüzü ile içeriğiniz arasında otomatik olarak geçiş yapar.
  4. isPresented ile kontrol etme: authService.isPresented = true/false ayarını yaparak kimlik doğrulama sayfasının ne zaman görüneceğini kontrol edin.

Öznel davranışlar

Varsayılan AuthPickerView, çeşitli karmaşık senaryoların nasıl ele alınacağı konusunda fikir verir:

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

Hesap çakışması olduğunda (ör. başka bir hesaba bağlı bir kimlik bilgisiyle oturum açma) AuthPickerView bunu otomatik olarak çözer:

  • 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 bilgilerini depolar ve başarılı bir oturum açma işleminden sonra bunları bağlamaya çalışır.

Bu işlem, NavigationStack düzeyinde uygulanan AccountConflictModifier tarafından gerçekleştirilir.

2. Çok faktörlü kimlik doğrulama (MFA)

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

  • Oturum açma sırasında MFA gerektiğinde otomatik olarak algılar.
  • Uygun MFA çözünürlük ekranlarını (SMS veya TOTP) gösterir.
  • MFA kaydı ve yönetim akışlarını yönetir.
  • 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şleme özelliğini 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ıyor
  • Hatalar, reportError ortam anahtarı aracılığıyla yayılır.

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

  • E-posta adresini uygulama depolama alanında otomatik olarak saklar.
  • E-postadan derin bağlantı gezinmesini yönetir
  • 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ı otomatik olarak yükseltme

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örlerinin kaydını iptal etme gibi hassas işlemler için yakın zamanda kimlik doğrulaması 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 onay isteyen bir uyarı gösterilir, ardından yeni kimlik bilgileri otomatik olarak alınır ve işlem tamamlanır.

  • E-posta/Şifre: Kullanıcıdan 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österilir, ardından SMS kodu doğrulama sayfası sunulur.

Yeniden kimlik doğrulama işlemi başarılı olduktan sonra işlem 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 kullanmaya devam ederken kendi özel kimlik doğrulama görünümlerinizi oluşturabilirsiniz.

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

1. yaklaşım: registerProvider() ile ö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üğmesinin nasıl oluşturulacağı aşağıda açıklanmıştır:

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

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 tüm sağlayıcılar için geçerlidir: Google, Apple, Twitter, Facebook, Telefon ve OAuth sağlayıcıları. Özel düğme görünümünüzü oluşturup AuthProviderUI ile uyumlu bir sınıfa sarmalamanız yeterlidir.

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

Kendi düzeninizi ve gezinme deneyiminizi sunarken varsayılan kimlik doğrulama düğmelerini oluşturmak için AuthService.renderButtons() 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 özelliğine sahip özel görünümler

Tüm akış üzerinde tam kontrol sahibi olmak için AuthPickerView hizmetini atlayıp kendi navigasyon 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 dikkat edilmesi gereken önemli noktalar

Özel görünümler oluştururken AuthPickerView tarafından otomatik olarak gerçekleştirilen bazı işlemleri kendiniz yapmanız gerekir:

  1. Hesap Çakışmaları: AuthServiceError.accountConflict kullanarak kendi çakışma çözme stratejinizi uygulayın.
  2. MFA İşleme: .mfaRequired için SignInOutcome adresini kontrol edin ve MFA çö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önetme
  5. Yükleme Durumları: authService.authenticationState öğesini gözlemleyerek eşzamansız kimlik doğrulama işlemleri sırasında yükleme göstergelerini gösterin.
  6. Yeniden kimlik doğrulama: Hassas işlemler için yeniden kimlik doğrulama hatalarını işleme (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:) yöntemini ç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:) yöntemini ç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:) yöntemini çağırı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ılara yönelik metin için bir .displayMessage özelliği içerir.

Özel OAuth sağlayıcıları

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

⚠️ Önemli: OIDC (OpenID Connect) sağlayıcılarını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ı, veren 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)
  }
}