FirebaseUI-এর মাধ্যমে আপনার iOS অ্যাপে সাইন-ইন করার সুবিধা যোগ করা

SwiftUI-এর জন্য FirebaseUI হল একটি আধুনিক, SwiftUI-ফার্স্ট লাইব্রেরি যা Firebase Authentication-এর উপরে তৈরি করা হয়েছে এবং এটি আপনার অ্যাপে আগে থেকেই তৈরি সাইন-ইন ফ্লো প্রদান করে।

SwiftUI-এর জন্য FirebaseUI-এর নিম্নলিখিত সুবিধাগুলি রয়েছে:

  • মতামত-ভিত্তিক ডিফল্ট UI: AuthPickerView-এর মাধ্যমে সম্পূর্ণ সাইন-ইন ফ্লো যোগ করুন।
  • কাস্টমাইজ করা যায়: আপনার নিজস্ব লেআউটে ডিফল্ট বোতাম রেন্ডার করুন অথবা সম্পূর্ণ কাস্টম অভিজ্ঞতা তৈরি করুন।
  • পরিচয় গোপন করা অ্যাকাউন্ট লিঙ্ক করা: পরিচয় গোপন করা ব্যবহারকারীদের সরিয়ে দেওয়ার পরিবর্তে ঐচ্ছিকভাবে তাদের অ্যাকাউন্ট আপগ্রেড করুন।
  • অ্যাকাউন্ট ম্যানেজমেন্ট: সাইন-আপ, পাসওয়ার্ড ফিরিয়ে আনা ও অ্যাকাউন্ট ম্যানেজমেন্টের জন্য বিল্ট-ইন ফ্লো।
  • একাধিক পরিষেবা প্রদানকারী: ইমেল/পাসওয়ার্ড, ইমেল লিঙ্ক, ফোন নম্বর যাচাইকরণ, Apple, Google, Facebook, Twitter এবং স্ট্যান্ডার্ড OAuth2/OIDC পরিষেবা প্রদানকারী।
  • আধুনিক যাচাইকরণ ফিচার: বহু-স্তরীয় যাচাইকরণ (MFA) এবং async/await API-এর জন্য বিল্ট-ইন সহায়তা।

শুরু করার আগে

  • আপনার Apple প্রোজেক্টে Firebase যোগ করুন। SwiftUI ধাপগুলি সম্পূর্ণ করতে ভুলবেন না।

  • আপনার অ্যাপ iOS 17 বা তার পরবর্তী যেকোনও ভার্সনের জন্য তৈরি করা হয়েছে কিনা তা ভালোভাবে দেখে নিন।

ইনস্টল করা

SwiftUI-এর জন্য FirebaseUI একটি Swift প্যাকেজ হিসেবে প্রদান করা হয়। আপনার Xcode প্রোজেক্টে প্যাকেজ ইনস্টল করতে, নিম্নলিখিত ধাপগুলি অনুসরণ করুন:

  1. Xcode-এ, ফাইল > প্যাকেজ ডিপেন্ডেন্সি যোগ করুন বিকল্পে ক্লিক করুন।

  2. প্যাকেজ URL লিখুন:

    https://github.com/firebase/FirebaseUI-iOS
    
  3. নির্ভরতা সংক্রান্ত নিয়ম মেনুতে, পরবর্তী মেজর ভার্সন পর্যন্ত বিকল্প বেছে নিন এবং ন্যূনতম ভার্সন হিসেবে লেটেস্ট রিলিজ সেট করুন।

  4. প্যাকেজ যোগ করুন বিকল্পে ক্লিক করুন, তারপর আপনার প্রোজেক্টে যোগ করার জন্য লাইব্রেরি বেছে নিন।

    নিচে উল্লেখ করা লাইব্রেরি সবসময় প্রয়োজন। এর মধ্যে মূল নির্ভরতা এবং ইমেল-পাসওয়ার্ড দিয়ে সাইন-ইন ও ইমেল লিঙ্ক দিয়ে সাইন-ইন করার সুবিধা অন্তর্ভুক্ত।

    • FirebaseAuthSwiftUI

     আপনি যদি অন্যান্য সাইন-ইন পদ্ধতিকেও কাজ করাতে চান, তাহলে নিম্নলিখিত লাইব্রেরিগুলির মধ্যে একটি বা একাধিক বেছে নিন:

    • FirebaseAppleSwiftUI (Apple-এর মাধ্যমে সাইন-ইন করুন)
    • FirebaseGoogleSwiftUI (Google-এর মাধ্যমে সাইন-ইন করুন)
    • FirebaseFacebookSwiftUI (Facebook-এর মাধ্যমে সাইন-ইন করুন)
    • FirebasePhoneAuthSwiftUI (ফোন নম্বর যাচাইকরণ)
    • FirebaseTwitterSwiftUI (Twitter-এর মাধ্যমে সাইন-ইন করুন)
    • FirebaseOAuthSwiftUI (GitHub, Microsoft, Yahoo-এর মতো স্ট্যান্ডার্ড OAuth এবং OIDC প্রদানকারী)
  5. বেছে নেওয়া লাইব্রেরি ইনস্টল করতে প্যাকেজ যোগ করুন বিকল্পে ক্লিক করুন।

  6. FirebaseUI-এর AuthService আপনার টপ-লেভেলের ইনিশিয়ালাইজারে কনফিগার করুন View এবং এনভায়রনমেন্ট ব্যবহার করে চাইল্ড ভিউতে পরিষেবা পাস করুন।

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

সাইন-ইন পদ্ধতি সেট-আপ করা

কাজ করে এমন প্রতিটি সাইন-ইন পদ্ধতির জন্য অতিরিক্ত সেট-আপ ধাপ প্রয়োজন। নিচে দেওয়া বিভাগগুলি বড় করে দেখুন এবং আলাদা আলাদা প্রোভাইডার সেট-আপ করার নির্দেশাবলী অনুসরণ করুন।

ইমেল আইডি ও পাসওয়ার্ড

  1. Firebase কনসোলের সুরক্ষা > যাচাইকরণ > সাইন-ইন পদ্ধতি বিভাগ থেকে, ইমেল/পাসওয়ার্ড প্রদানকারীকে চালু করুন।

  2. আপনার AuthService ইনস্ট্যান্সে পরিষেবা প্রদানকারীকে রেজিস্টার করুন:

    let authService = AuthService()
      .withEmailSignIn()
    

পাসওয়ার্ড ছাড়া ইমেল লিঙ্ক সাইন-ইন ব্যবহার করতে:

  1. Firebase কনসোলের নিরাপত্তা > যাচাইকরণ > সাইন-ইন পদ্ধতি বিভাগ থেকে, ইমেল/পাসওয়ার্ড বিকল্প চালু করুন, তারপর ইমেল লিঙ্ক দিয়ে সাইন-ইন করার বিকল্প চালু করুন। মনে রাখবেন, ইমেল লিঙ্ক সাইন-ইন ব্যবহার করতে হলে ইমেল বা পাসওয়ার্ড দিয়ে সাইন-ইন করার সুবিধা চালু থাকতে হবে।

  2. অনুমোদিত ডোমেনে লিঙ্ক ডোমেন যোগ করুন।

  3. ActionCodeSettings কনফিগার করুন, এটি AuthConfiguration-এ পাস করুন এবং প্রদানকারীকে রেজিস্টার করুন:

    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. আপনি যে AppDelegate থেকে কল করেন, সেই একই FirebaseApp.configure()-এ, application(_:open:options:) মেথডে এমন লজিক যোগ করুন যা Firebase Authentication সাইন-ইন লিঙ্ক খোলা হলে true রিটার্ন করে। এই লজিক থেকে বোঝা যায় যে FirebaseUI লিঙ্কটি ম্যানেজ করেছে এবং অন্যান্য লিঙ্ক হ্যান্ডলারদের এটি প্রসেস করার প্রয়োজন নেই।

    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. আপনি কাস্টম ভিউ তৈরি করলে, লিঙ্কটি আপনার অ্যাপ খুললে authService.handleSignInLink(url:)-এ কল করুন।

Apple

Apple-এর মাধ্যমে সাইন-ইন করুন ফিচার ব্যবহার করতে:

  1. 'Apple-এর মাধ্যমে সাইন-ইন করুন' কনফিগার করুন:

    1. Apple-এর ডেভেলপার সাইটের সার্টিফিকেট, শনাক্তকারী ও প্রোফাইল পৃষ্ঠায় আপনার অ্যাপের জন্য 'Apple-এর মাধ্যমে সাইন-ইন করুন' ফিচার চালু করুন।
    2. ওয়েবের জন্য Apple দিয়ে সাইন-ইন কনফিগার করুন নিবন্ধের প্রথম বিভাগে বর্ণিত পদ্ধতি অনুযায়ী আপনার অ্যাপের সাথে আপনার ওয়েবসাইট অ্যাসোসিয়েট করুন। প্রম্পট করা হলে, রিটার্ন URL হিসেবে নিম্নলিখিত URL রেজিস্টার করুন:
      https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/__/auth/handler
      আপনি Firebase কনসোল সেটিংস পৃষ্ঠায় আপনার Firebase প্রোজেক্ট আইডি পেতে পারেন। হয়ে গেলে, আপনার নতুন সার্ভিস আইডি লিখে রাখুন, যেটি পরের বিভাগে আপনার প্রয়োজন হবে।
    3. Sign in with Apple প্রাইভেট কী তৈরি করুন। পরবর্তী বিভাগে আপনার নতুন ব্যক্তিগত কী ও কী আইডি প্রয়োজন হবে।
    4. আপনি যদি Firebase Authentication-এর এমন কোনও ফিচার ব্যবহার করেন যা ব্যবহারকারীদের ইমেল পাঠায়, যার মধ্যে ইমেল লিঙ্ক সাইন-ইন, ইমেল আইডি যাচাইকরণ, অ্যাকাউন্ট পরিবর্তন প্রত্যাহার এবং অন্যান্য অন্তর্ভুক্ত, তাহলে Apple-এর ব্যক্তিগত ইমেল রিলে পরিষেবা কনফিগার করুন এবং রেজিস্টার করুন noreply@YOUR_FIREBASE_PROJECT_ID.firebaseapp.com (অথবা আপনার কাস্টমাইজ করা ইমেল টেমপ্লেট ডোমেন) যাতে Apple, Firebase Authentication-এর পাঠানো ইমেল অনামক Apple ইমেল আইডিতে রিলে করতে পারে।
  2. Firebase কনসোলের নিরাপত্তা > যাচাইকরণ > সাইন-ইন পদ্ধতি বিভাগ থেকে, Apple চালু করুন।

    • আগের বিভাগে আপনার তৈরি করা পরিষেবা আইডি উল্লেখ করুন।
    • OAuth কোড ফ্লো কনফিগারেশন বিভাগে, আপনার Apple টিম আইডি এবং আগের বিভাগে আপনার তৈরি করা ব্যক্তিগত কী ও কী আইডি উল্লেখ করুন।
  3. Xcode-এ, প্রোজেক্ট এডিটরের স্বাক্ষর ও ক্ষমতা বিভাগ খুলুন এবং Apple-এর মাধ্যমে সাইন-ইন করুন ক্ষমতা যোগ করুন।

  4. আপনার AuthService ইনস্ট্যান্সে পরিষেবা প্রদানকারীকে রেজিস্টার করুন:

    let authService = AuthService()
      .withAppleSignIn()
    

Google

Google সাইন-ইন ব্যবহার করতে:

  1. Firebase কনসোলের নিরাপত্তা > যাচাইকরণ > সাইন-ইন পদ্ধতি বিভাগ থেকে, Google পরিষেবা প্রদানকারীকে চালু করুন।

  2. আপনার প্রোজেক্টের GoogleService-Info.plist ফাইলের একটি নতুন কপি ডাউনলোড করুন এবং সেটি আপনার Xcode প্রোজেক্টে কপি করুন। নতুন ভার্সন দিয়ে আগে থেকে থাকা যেকোনও ভার্সন ওভাররাইট করুন।

  3. আপনার Xcode প্রোজেক্টে কাস্টম URL স্কিম যোগ করুন:

    1. আপনার প্রোজেক্ট কনফিগারেশন খুলুন: বাঁদিকের ট্রি ভিউতে প্রোজেক্টের নামে ক্লিক করুন। টার্গেট বিভাগ থেকে আপনার অ্যাপ বেছে নিন, তারপরে তথ্য ট্যাব বেছে নিন এবং URL-এর ধরন বিভাগটি বড় করুন।

    2. + বোতামে ক্লিক করুন এবং আপনার রিভার্সড ক্লায়েন্ট আইডির জন্য একটি URL স্কিম যোগ করুন। এই ভ্যালু খুঁজে পেতে, GoogleService-Info.plist কনফিগারেশন ফাইল খুলুন এবং REVERSED_CLIENT_ID কী দেখুন। সেই কী-এর ভ্যালু কপি করুন, এবং কনফিগারেশন পৃষ্ঠায় URL স্কিম বক্সে পেস্ট করুন। অন্যান্য ফিল্ডে কোনও পরিবর্তন করবেন না।

      সম্পূর্ণ হয়ে গেলে, আপনার কনফিগারেশনটি নিম্নলিখিত বিষয়গুলির মতো দেখতে হবে (তবে আপনার অ্যাপ্লিকেশন-নির্দিষ্ট ভ্যালু সহ):

  4. আপনার AuthService ইনস্ট্যান্সে পরিষেবা প্রদানকারীকে রেজিস্টার করুন:

    let authService = AuthService()
      .withGoogleSignIn()
    

Facebook

Facebook লগ-ইন ব্যবহার করতে:

  1. Meta for Developers সাইটে দেওয়া নির্দেশাবলী অনুসরণ করে iOS SDK-এর জন্য Facebook লগ-ইন সেট-আপ করুন। শেষ ধাপ, "আপনার কোডে Facebook লগ-ইন যোগ করুন" এড়িয়ে যান।

  2. Firebase কনসোলের নিরাপত্তা > যাচাইকরণ > সাইন-ইন পদ্ধতি বিভাগ থেকে, Facebook প্রদানকারীকে চালু করুন। Meta for Developers সাইট থেকে Facebook অ্যাপ আইডি ও অ্যাপ সিক্রেট নিতে হবে।

  3. আপনার AuthService ইনস্ট্যান্সে পরিষেবা প্রদানকারীকে রেজিস্টার করুন:

    let authService = AuthService()
     .withFacebookSignIn()
    

ফোন নম্বর

ফোন নম্বর যাচাইকরণ ব্যবহার করতে:

  1. Firebase কনসোলের সুরক্ষা > যাচাইকরণ > সাইন-ইন পদ্ধতি বিভাগ থেকে, ফোন পরিষেবা প্রদানকারীকে চালু করুন।

  2. সাইলেন্ট বিজ্ঞপ্তি পাওয়া শুরু করুন বিভাগে দেওয়া নির্দেশাবলী অনুযায়ী আপনার অ্যাপের জন্য APN কনফিগার করুন।

  3. আপনার Xcode প্রোজেক্টে কাস্টম URL স্কিম যোগ করুন:

    1. আপনার প্রোজেক্ট কনফিগারেশন খুলুন: বাঁদিকের ট্রি ভিউতে প্রোজেক্টের নামে ক্লিক করুন। টার্গেট বিভাগ থেকে আপনার অ্যাপ বেছে নিন, তারপরে তথ্য ট্যাব বেছে নিন এবং URL-এর ধরন বিভাগটি বড় করুন।

    2. + বোতামে ক্লিক করুন এবং URL স্কিম হিসেবে আপনার এনকোড করা অ্যাপ আইডি যোগ করুন। এই ভ্যালু খুঁজে পেতে, Firebase কনসোলে সেটিংস > সাধারণ বিকল্প খুলুন।

      সম্পূর্ণ হয়ে গেলে, আপনার কনফিগারেশনটি নিম্নলিখিত বিষয়গুলির মতো দেখতে হবে (তবে আপনার অ্যাপ্লিকেশন-নির্দিষ্ট ভ্যালু সহ):

  4. আপনি যে AppDelegate-এ FirebaseApp.configure() কল করেন, সেটিতে APNs টোকেন হ্যান্ডলার যোগ করুন:

    import FacebookCore
    import FirebaseAuth
    import UIKit
    
    class AppDelegate: NSObject, UIApplicationDelegate {
      func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
      ) -> Bool {
        FirebaseApp.configure()
        return true
      }
    
      func application(
        _ application: UIApplication,
        didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
      ) {
        #if DEBUG
        Auth.auth().setAPNSToken(deviceToken, type: .sandbox)
        #else
        Auth.auth().setAPNSToken(deviceToken, type: .prod)
        #endif
      }
    }
    
  5. আপনার AuthService ইনস্ট্যান্সে পরিষেবা প্রদানকারীকে রেজিস্টার করুন:

    let authService = AuthService()
      .withPhoneSignIn()
    

Twitter (X)

Twitter লগ-ইন ব্যবহার করতে:

  1. X Developers সাইটে দেওয়া নির্দেশাবলী অনুসরণ করে X API ক্রেডেনশিয়াল জেনারেট করুন।

  2. Firebase কনসোলের নিরাপত্তা > যাচাইকরণ > সাইন-ইন পদ্ধতি বিভাগ থেকে, Twitter প্রদানকারীকে চালু করুন। X Developer Console থেকে API key ও API সিক্রেট লাগবে।

  3. আপনার AuthService ইনস্ট্যান্সে পরিষেবা প্রদানকারীকে রেজিস্টার করুন:

    let authService = AuthService()
      .withTwitterSignIn()
    

স্ট্যান্ডার্ড OAuth2 ও OIDC প্রোভাইডার

এছাড়াও, FirebaseUI-তে GitHub, Microsoft এবং Yahoo-এর মতো বিল্ট-ইন OAuth প্রদানকারী এবং Firebase Authentication-এ কনফিগার করা কাস্টম OIDC প্রদানকারী কাজ করে।

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

কাস্টম OIDC প্রদানকারীর জন্য, প্রথমে Firebase Authentication-এ প্রদানকারীকে কনফিগার করুন, তারপর আপনার প্রদানকারী আইডি ও বোতাম কনফিগারেশন সহ OAuthProviderSwift তৈরি করুন:

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)

আগে থেকে তৈরি যাচাইকরণ ভিউ ব্যবহার করা

SwiftUI-এর জন্য FirebaseUI AuthPickerView প্রদান করে, এটি একটি আগে থেকে তৈরি করা, মতামত ভিত্তিক যাচাইকরণ UI যা আপনার জন্য সম্পূর্ণ যাচাইকরণ ফ্লো ম্যানেজ করে। আপনার অ্যাপে যাচাইকরণ যোগ করার এটিই সবচেয়ে সহজ উপায়।

উদাহরণ

একাধিক পরিষেবা প্রদানকারী ও কনফিগারেশন বিকল্প সহ AuthPickerView ব্যবহারের একটি উদাহরণ এখানে দেওয়া হল:

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

সাধারণ কাস্টমাইজেশন

যদিও সব AuthConfiguration প্যারামিটার ঐচ্ছিক, তবে বেশিরভাগ অ্যাপ নিম্নলিখিত সেটিংস কমপক্ষে কাস্টমাইজ করে:

let configuration = AuthConfiguration(
    logo: ImageResource.exampleLogoAsset,
    customStringsBundle: .main,
    tosUrl: URL(string: "https://example.com/tos"),
    privacyPolicyUrl: URL(string: "https://example.com/privacy"),
)
  • logo: যাচাইকরণ শিটে দেখানো লোগোর ছবি। আপনার নিজের ইমেজ অ্যাসেট যোগ করা সংক্রান্ত তথ্যের জন্য, আপনার Xcode প্রোজেক্টে ছবি যোগ করা দেখুন।

  • customStringsBundle: নির্দিষ্ট বান্ডেল থেকে কাস্টম স্ট্রিং ব্যবহার করুন। এটি লোকালাইজেশনের জন্য ব্যবহার করা হয়, তবে AuthPickerView-এর ব্যবহার করা ডিফল্ট স্ট্রিং কাস্টমাইজ করার জন্যও ব্যবহার করা হয়। যেমন, যাচাইকরণ শিটের উপরে দেখানো মেসেজ সেট করতে, এই কন্টেন্ট সহ Localizable.strings তৈরি করুন:

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

আগে থেকে তৈরি ভিউতে কী কী অন্তর্ভুক্ত থাকে

AuthPickerView ব্যবহার করলে আপনি এগুলি পাবেন:

  1. শিট প্রেজেন্টেশন: যাচাইকরণ UI মোডাল শিট হিসেবে দেখা যায়
  2. বিল্ট-ইন নেভিগেশন: সাইন-ইন, পাসওয়ার্ড ফিরিয়ে আনা, MFA, ইমেল লিঙ্ক ও ফোন নম্বর যাচাইকরণ স্ক্রিনের মধ্যে অটোমেটিক নেভিগেশন
  3. প্রমাণীকরণ স্টেট ম্যানেজমেন্ট: authService.authenticationState-এর উপর ভিত্তি করে প্রমাণীকরণ UI ও আপনার কন্টেন্টের মধ্যে অটোমেটিক পাল্টে যায়
  4. isPresented-এর মাধ্যমে নিয়ন্ত্রণ করুন: authService.isPresented = true/false সেট করার মাধ্যমে কখন অনুমোদনের শিট দেখা যাবে তা নিয়ন্ত্রণ করুন

মতবাদ সম্পর্কিত আচরণ

ডিফল্ট AuthPickerView একাধিক জটিল পরিস্থিতি কীভাবে সামলাতে হয় সেই ব্যাপারে নির্দিষ্ট মতামত দেয়:

১. অ্যাকাউন্ট সংক্রান্ত সমস্যার সমাধান

অ্যাকাউন্ট সংক্রান্ত সমস্যা হলে (যেমন, এমন ক্রেডেনশিয়াল দিয়ে সাইন-ইন করা যা আগে থেকেই অন্য অ্যাকাউন্টের সাথে লিঙ্ক করা আছে), AuthPickerView অটোমেটিক তা ম্যানেজ করে:

  • পরিচয় গোপন রেখে আপগ্রেড সংক্রান্ত বিরোধ: shouldAutoUpgradeAnonymousUsers চালু করা থাকলে এবং পরিচয় গোপন রেখে আপগ্রেড করার সময় কোনও বিরোধ হলে, সিস্টেম অটোমেটিক পরিচয় গোপন রাখা ব্যবহারকারীকে সাইন-আউট করে দেয় এবং নতুন ক্রেডেনশিয়াল দিয়ে সাইন-ইন করে।
  • অন্যান্য কনফ্লিক্ট: বেনামী নয় এমন অ্যাকাউন্টের মধ্যে ক্রেডেনশিয়াল সংক্রান্ত কনফ্লিক্ট হলে, সিস্টেম বাকি থাকা ক্রেডেনশিয়াল সেভ করে এবং সফলভাবে সাইন-ইন করার পরে সেটি লিঙ্ক করার চেষ্টা করে।

এটি AccountConflictModifier দ্বারা হ্যান্ডেল করা হয় যা NavigationStack লেভেলে প্রয়োগ করা হয়।

২. বহু-স্তরীয় যাচাইকরণ (MFA)

আপনার কনফিগারেশনে MFA চালু করা থাকলে:

  • সাইন-ইন করার সময় MFA-এর প্রয়োজন হলে তা অটোমেটিক শনাক্ত করে
  • উপযুক্ত MFA সমাধান স্ক্রিন (SMS বা TOTP) দেখায়
  • MFA এনরোলমেন্ট ও ম্যানেজমেন্ট ফ্লো ম্যানেজ করে
  • এসএমএস-ভিত্তিক ও সময়-ভিত্তিক একবার ব্যবহারের পাসওয়ার্ড (TOTP) ফ্যাক্টর, দু'টিই কাজ করে
৩. সমস্যা ম্যানেজ করা

ডিফল্ট ভিউতে বিল্ট-ইন সমস্যা সমাধান অন্তর্ভুক্ত থাকে:

  • সতর্কতা ডায়ালগে ব্যবহারকারী-বান্ধব সমস্যার মেসেজ দেখায়
  • অভ্যন্তরীণভাবে ম্যানেজ করা হয় এমন সমস্যা অটোমেটিক ফিল্টার করে বাদ দেয় (যেমন, বাতিলকরণ সংক্রান্ত সমস্যা, অটোমেটিক ম্যানেজ করা বিরোধ)
  • StringUtils-এর মাধ্যমে স্থানীয় ভাষায় সমস্যার মেসেজ ব্যবহার করে
  • reportError এনভায়রনমেন্ট কী-এর মাধ্যমে সমস্যাগুলি ছড়িয়ে পড়ে

ইমেল লিঙ্ক দিয়ে সাইন-ইন করার সুবিধা কনফিগার করা থাকলে:

  • অ্যাপ স্টোরেজে ইমেল আইডি অটোমেটিক সেভ করে
  • ইমেল থেকে ডিপ লিঙ্ক নেভিগেশন ম্যানেজ করে
  • সম্পূর্ণ ইমেল যাচাইকরণ ফ্লো ম্যানেজ করে
  • ইমেল লিঙ্কের মাধ্যমে পরিচয় গোপন রাখা ব্যবহারকারীদের আপগ্রেড করার সুবিধা আছে
৫. পরিচয় গোপন করা ব্যবহারকারীর অটোমেটিক আপগ্রেড

shouldAutoUpgradeAnonymousUsers চালু করা থাকলে:

  • নতুন সাইন-ইন ক্রেডেনশিয়ালের সাথে অটোমেটিক বেনামী অ্যাকাউন্ট লিঙ্ক করার চেষ্টা করে
  • অপরিচিত সেশন পাল্টে দেওয়ার পরিবর্তে আপগ্রেড করার মাধ্যমে ব্যবহারকারীর ডেটা সুরক্ষিত রাখে
  • আপগ্রেড সংক্রান্ত সমস্যাগুলি দক্ষতার সাথে ম্যানেজ করে
৬. ডিফল্ট ভিউতে আবার যাচাইকরণ

অ্যাকাউন্ট মুছে দেওয়া, পাসওয়ার্ড আপডেট করা বা MFA ফ্যাক্টর আনএনরোল করার মতো সংবেদনশীল অপারেশনের জন্য সাম্প্রতিক যাচাইকরণ প্রয়োজন। ডিফল্ট ভিউ ব্যবহার করার সময়, ব্যবহারকারীর সাইন-ইন প্রদানকারীর উপর ভিত্তি করে আবার যাচাইকরণ অটোমেটিক ম্যানেজ করা হয়।

কোনও সংবেদনশীল অপারেশনের জন্য আবার যাচাইকরণ প্রয়োজন হলে, ডিফল্ট ভিউ অটোমেটিক:

  • OAuth প্রদানকারী (Google, Apple, Facebook, Twitter, ইত্যাদি): ব্যবহারকারীকে কনফার্ম করতে বলে একটি সতর্কতা দেখান, তারপরে অটোমেটিক নতুন ক্রেডেনশিয়াল পান এবং অপারেশন সম্পূর্ণ করুন।

  • ইমেল/পাসওয়ার্ড: চালিয়ে যাওয়ার আগে ব্যবহারকারীকে পাসওয়ার্ড লেখার জন্য প্রম্পট করে এমন একটি শিট দেখান।

  • ইমেল লিঙ্ক: যাচাইকরণ ইমেল পাঠানোর জন্য অনুরোধ করে একটি সতর্কতা দেখান, তারপর ইমেল চেক করার নির্দেশাবলী সহ একটি শিট দেখান। আবার যাচাইকরণ সম্পূর্ণ করতে ব্যবহারকারী ইমেলে থাকা লিঙ্কে ট্যাপ করেন।

  • ফোন: যাচাইকরণ প্রয়োজন, তা ব্যাখ্যা করে একটি সতর্কতা দেখান, তারপর এসএমএস কোড যাচাইকরণের জন্য একটি শিট দেখান।

সফলভাবে আবার যাচাইকরণের পরে অপারেশন অটোমেটিক আবার চেষ্টা করে। AuthPickerView বা বিল্ট-ইন অ্যাকাউন্ট ম্যানেজমেন্ট ভিউ (UpdatePasswordView, SignedInView, ইত্যাদি) ব্যবহার করার সময় কোনও অতিরিক্ত কোডের প্রয়োজন হয় না।

উন্নত: কাস্টম অথ ভিউ তৈরি করা

UI বা নেভিগেশন ফ্লোয়ের উপর আরও নিয়ন্ত্রণ পেতে চাইলে, আপনি নিজের কাস্টম যাচাইকরণ ভিউ তৈরি করতে পারেন, তবে যাচাইকরণ লজিকের জন্য AuthService ব্যবহার করতে হবে।

আপনি FirebaseUI-এর এলিমেন্টকে কাস্টম লজিকের সাথে বিভিন্ন উপায়ে মিশিয়ে নিতে পারেন। নিচে দেওয়া বিভাগে কাস্টমাইজেশনের কিছু পদ্ধতির উদাহরণ দেওয়া আছে যা আপনি ব্যবহার করতে পারেন।

পদ্ধতি ১: registerProvider() সহ কাস্টম বোতাম

বোতামের চেহারা সম্পূর্ণভাবে নিয়ন্ত্রণ করতে, আপনি নিজের কাস্টম AuthProviderUI প্রয়োগ তৈরি করতে পারেন যা যেকোনও পরিষেবা প্রদানকারীকে র‍্যাপ করে এবং আপনার কাস্টম বোতাম ভিউ রিটার্ন করে।

কাস্টম প্রদানকারী UI তৈরি করা

উদাহরণ হিসেবে কাস্টম Twitter বোতাম কীভাবে তৈরি করবেন তা এখানে দেওয়া হল:

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

সহজ কাস্টম বোতামের উদাহরণ

এছাড়াও, আপনি যেকোনও পরিষেবা প্রদানকারীর জন্য আরও সহজ কাস্টম বোতাম তৈরি করতে পারেন:

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

এই পদ্ধতি সব পরিষেবা প্রদানকারীর ক্ষেত্রে কাজ করে: Google, Apple, Twitter, Facebook, ফোন এবং OAuth পরিষেবা প্রদানকারী। সহজেই আপনার কাস্টম বোতাম ভিউ তৈরি করুন এবং AuthProviderUI মেনে চলা একটি ক্লাসে তা র‍্যাপ করুন।

পদ্ধতি ২: কাস্টম ভিউ সহ ডিফল্ট বোতাম

আপনি নিজের লেআউট ও নেভিগেশন প্রদান করার সময় ডিফল্ট যাচাইকরণ বোতাম রেন্ডার করতে AuthService.renderButtons() ও বাইপাস AuthPickerView ব্যবহার করতে পারবেন:

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

পদ্ধতি ৩: কাস্টম নেভিগেশন সহ কাস্টম ভিউ

সম্পূর্ণ ফ্লোয়ের উপর সম্পূর্ণ নিয়ন্ত্রণ পেতে, আপনি AuthPickerView এড়িয়ে গিয়ে নিজের নেভিগেশন সিস্টেম তৈরি করতে পারেন:

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

কাস্টম ভিউয়ের জন্য গুরুত্বপূর্ণ বিবেচনা

কাস্টম ভিউ তৈরি করার সময়, আপনাকে এমন অনেক কিছু নিজে থেকে ম্যানেজ করতে হবে যা AuthPickerView অটোমেটিক ম্যানেজ করে:

  1. অ্যাকাউন্ট সংক্রান্ত বিরোধ: AuthServiceError.accountConflict ব্যবহার করে আপনার নিজস্ব বিরোধ নিষ্পত্তি কৌশল প্রয়োগ করুন
  2. MFA ম্যানেজ করা: .mfaRequired-এর জন্য SignInOutcome চেক করুন এবং MFA সংক্রান্ত সমস্যার সমাধান ম্যানুয়ালি করুন
  3. অপরিচিত ব্যবহারকারীর আপগ্রেড: shouldAutoUpgradeAnonymousUsers চালু থাকলে, অপরিচিত অ্যাকাউন্ট লিঙ্কিং ম্যানেজ করা
  4. নেভিগেশন স্টেট: বিভিন্ন অথেন্টিকেশন স্ক্রিনের (ফোন নম্বর যাচাইকরণ, পাসওয়ার্ড ফিরিয়ে আনা ইত্যাদি) মধ্যে নেভিগেশন ম্যানেজ করা
  5. লোডিং স্টেট: অ্যাসিঙ্ক যাচাইকরণ অপারেশন চলাকালীন authService.authenticationState দেখে লোডিং ইন্ডিকেটর দেখান
  6. আবার যাচাইকরণ: সংবেদনশীল অপারেশনের জন্য আবার যাচাইকরণ সংক্রান্ত সমস্যা সমাধান করুন (নিচে কাস্টম ভিউতে আবার যাচাইকরণ দেখুন)

কাস্টম ভিউতে আবার যাচাইকরণ

কাস্টম ভিউ তৈরি করার সময়, নির্দিষ্ট সমস্যা ধরে নিয়ে এবং আপনার নিজস্ব ফ্লো প্রয়োগ করে আবার যাচাইকরণ প্রসেস ম্যানেজ করুন। সংবেদনশীল অপারেশনের ক্ষেত্রে চার ধরনের আবার যাচাইকরণ সংক্রান্ত সমস্যা হয়, প্রত্যেকটিতে প্রাসঙ্গিক তথ্য থাকে।

প্রয়োগ সংক্রান্ত প্যাটার্ন

OAuth প্রদানকারী (Google, Apple, Facebook, Twitter, ইত্যাদি):

সমস্যাটি ধরে নিন এবং reauthenticate(context:) কল করুন যা অটোমেটিক 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
  }
}

ইমেল/পাসওয়ার্ড:

সমস্যাটি ধরে, পাসওয়ার্ডের জন্য প্রম্পট করে, ক্রেডেনশিয়াল তৈরি করে এবং 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
  }
}

ফোন:

সমস্যাটি শনাক্ত করুন, ফোন নম্বর যাচাই করুন, ক্রেডেনশিয়াল তৈরি করুন এবং 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
  }
}

ইমেল লিঙ্ক:

সমস্যাটি শনাক্ত করুন, যাচাইকরণ ইমেল পাঠান এবং ইনকামিং URL ম্যানেজ করুন:

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

সব রিয়েথেন্টিকেশন কনটেক্সট অবজেক্টে ব্যবহারকারীর জন্য টেক্সট দেখানোর .displayMessage প্রপার্টি থাকে।

কাস্টম OAuth পরিষেবা প্রদানকারী

বিল্ট-ইন পরিষেবা ছাড়াও অন্যান্য পরিষেবার জন্য আপনি কাস্টম OAuth প্রদানকারী তৈরি করতে পারবেন:

⚠️ গুরুত্বপূর্ণ: OIDC (OpenID Connect) প্রদানকারীকে ব্যবহার করার আগে আপনার Firebase প্রোজেক্টের 'পরিচয় যাচাইকরণ' সেটিংসে কনফিগার করতে হবে। Firebase Console-এ, যাচাইকরণ → সাইন-ইন পদ্ধতি বিকল্পে যান এবং প্রয়োজনীয় ক্রেডেনশিয়াল (ক্লায়েন্ট আইডি, ক্লায়েন্ট সিক্রেট, ইস্যুকারী URL) সহ আপনার OIDC প্রদানকারীকে যোগ করুন। এছাড়াও, আপনাকে অবশ্যই Firebase-এর দেওয়া OAuth রিডাইরেক্ট URI আপনার প্রদানকারীর ডেভেলপার কনসোলে রেজিস্টার করতে হবে। সেট-আপ সংক্রান্ত বিস্তারিত নির্দেশাবলীর জন্য 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)
  }
}