FirebaseUI لـ SwiftUI هي مكتبة حديثة تعتمد على SwiftUI ومبنية على Firebase Authentication، وتوفّر مسارات تسجيل دخول مُعدّة مسبقًا لتطبيقك.
توفّر FirebaseUI for SwiftUI المزايا التالية:
- واجهة مستخدم تلقائية مخصّصة: يمكنك إضافة عملية تسجيل دخول كاملة باستخدام
AuthPickerView. - قابلة للتخصيص: يمكنك عرض الأزرار التلقائية في تصميمك الخاص أو إنشاء تجربة مخصّصة بالكامل.
- ربط الحسابات المجهولة الهوية: يمكنك ترقية المستخدمين المجهولي الهوية بدلاً من استبدالهم.
- إدارة الحساب: عمليات مدمجة للاشتراك واسترداد كلمة المرور وإدارة الحساب
- مقدّمو خدمات متعدّدون: البريد الإلكتروني/كلمة المرور، ورابط البريد الإلكتروني، والمصادقة عبر الهاتف، وApple، وGoogle، وFacebook، وTwitter، ومقدّمو خدمات OAuth2/OIDC العاديون.
- ميزات المصادقة الحديثة: تتيح استخدام المصادقة المتعدّدة العوامل (MFA) وواجهات برمجة التطبيقات غير المتزامنة/الانتظار.
قبل البدء
أضِف Firebase إلى مشروع Apple. تأكَّد من إكمال خطوات SwiftUI.
تأكَّد من أنّ تطبيقك يستهدف الإصدار 17 من نظام التشغيل iOS أو إصدارًا أحدث.
تثبيت
يتم توفير FirebaseUI لـ SwiftUI كحزمة Swift. لتثبيت الحزمة في مشروع Xcode، اتّبِع الخطوات التالية:
في Xcode، انقر على ملف > إضافة موارد الاعتمادية للحزمة (File > Add Package Dependencies).
أدخِل عنوان URL للحزمة:
https://github.com/firebase/FirebaseUI-iOSفي قائمة قاعدة التبعية، اختَر حتى رقم الإصدار الرئيسي التالي واضبط الحد الأدنى للإصدار على أحدث إصدار.
انقر على إضافة حزمة (Add Package)، ثم اختَر المكتبات التي تريد إضافتها إلى مشروعك.
المكتبة التالية مطلوبة دائمًا. وتتضمّن التبعيات الأساسية بالإضافة إلى إمكانية تسجيل الدخول باستخدام البريد الإلكتروني وكلمة المرور وتسجيل الدخول باستخدام رابط البريد الإلكتروني.
FirebaseAuthSwiftUI
إذا أردت إتاحة طرق أخرى لتسجيل الدخول، اختَر أيضًا مكتبة واحدة أو أكثر من المكتبات التالية:
-
FirebaseAppleSwiftUI(تسجيل الدخول باستخدام Apple) -
FirebaseGoogleSwiftUI(تسجيل الدخول باستخدام حساب Google) FirebaseFacebookSwiftUI(تسجيل الدخول باستخدام Facebook)-
FirebasePhoneAuthSwiftUI(المصادقة عبر الهاتف) FirebaseTwitterSwiftUI(تسجيل الدخول باستخدام Twitter)-
FirebaseOAuthSwiftUI(موفّرو OAuth وOIDC العاديون، مثل GitHub وMicrosoft وYahoo)
انقر على Add Package (إضافة حزمة) لتثبيت المكتبات المحدّدة.
اضبط
AuthServiceفي FirebaseUI في دالة الإعداد لمستوى التطبيق الأعلى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) } }
إعداد طُرق تسجيل الدخول
تتطلّب كل طريقة من طرق تسجيل الدخول المتوافقة بعض خطوات الإعداد الإضافية. يمكنك توسيع الأقسام أدناه واتّباع التعليمات لإعداد مقدّمي الخدمات الفرديين.
عنوان البريد الإلكتروني وكلمة المرور
من قسم الأمان > المصادقة > طريقة تسجيل الدخول في وحدة تحكّم Firebase، فعِّل مزوّد البريد الإلكتروني/كلمة المرور.
سجِّل موفِّر الخدمة في مثيل
AuthService:let authService = AuthService() .withEmailSignIn()
المصادقة عبر رابط في رسالة إلكترونية
لتسجيل الدخول باستخدام رابط البريد الإلكتروني بدون كلمة مرور، اتّبِع الخطوات التالية:
من قسم الأمان > المصادقة > طريقة تسجيل الدخول في وحدة تحكّم Firebase، فعِّل البريد الإلكتروني/كلمة المرور، ثم فعِّل تسجيل الدخول عبر رابط البريد الإلكتروني. يُرجى العِلم أنّه يجب تفعيل تسجيل الدخول باستخدام البريد الإلكتروني أو كلمة المرور لاستخدام تسجيل الدخول باستخدام رابط البريد الإلكتروني.
أضِف نطاق الرابط إلى النطاقات المعتمَدة.
اضبط
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()في
AppDelegateنفسه الذي تستدعي فيهFirebaseApp.configure()، أضِف منطقًا إلى طريقةapplication(_:open:options:)التي تعرضtrueعندما يكون عنوان URL الذي تم فتحه هو رابط تسجيل دخول إلى Firebase Authentication. يشير هذا المنطق إلى أنّ الرابط تمت معالجته بواسطة 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 } }إذا كنت تنشئ طرق عرض مخصّصة، يمكنك استدعاء
authService.handleSignInLink(url:)عندما يفتح الرابط تطبيقك.
Apple
لاستخدام ميزة "تسجيل الدخول باستخدام Apple"، اتّبِع الخطوات التالية:
ضبط ميزة "تسجيل الدخول باستخدام Apple":
- فعِّل ميزة "تسجيل الدخول باستخدام Apple" لتطبيقك في صفحة الشهادات والمعرّفات والملفات الشخصية على موقع Apple الإلكتروني للمطوّرين.
- اربط موقعك الإلكتروني بتطبيقك كما هو موضّح في القسم الأول من مقالة إعداد ميزة "تسجيل الدخول باستخدام Apple" للويب. عندما يُطلب منك ذلك، سجِّل عنوان URL التالي كعنوان URL للعودة:
يمكنك الحصول على رقم تعريف مشروع Firebase الخاص بك من صفحة إعدادات وحدة تحكّم Firebase. عند الانتهاء، دوِّن معرّف الخدمة الجديد الذي ستحتاج إليه في القسم التالي.https://YOUR_FIREBASE_PROJECT_ID.firebaseapp.com/__/auth/handler
- أنشئ مفتاحًا خاصًا لميزة "تسجيل الدخول باستخدام Apple". ستحتاج إلى المفتاح الخاص الجديد ومعرّف المفتاح في القسم التالي.
- إذا كنت تستخدم أيًا من ميزات Firebase Authentication التي ترسل رسائل إلكترونية إلى المستخدمين،
بما في ذلك تسجيل الدخول عبر رابط البريد الإلكتروني والتحقّق من عنوان البريد الإلكتروني وإبطال
تغيير الحساب وغيرها، اضبط خدمة Apple الخاصة لإرسال الرسائل الإلكترونية
وسجِّل
noreply@YOUR_FIREBASE_PROJECT_ID.firebaseapp.com(أو نطاق نموذج البريد الإلكتروني المخصّص) حتى تتمكّن Apple من إرسال الرسائل الإلكترونية التي يرسلها Firebase Authentication إلى عناوين البريد الإلكتروني المجهولة الهوية على Apple.
من قسم الأمان > المصادقة > طريقة تسجيل الدخول في وحدة تحكّم Firebase، فعِّل Apple.
- حدِّد رقم تعريف الخدمة الذي أنشأته في القسم السابق.
- في قسم إعدادات مسار رمز OAuth، حدِّد رقم تعريف فريق Apple والمفتاح الخاص ورقم تعريف المفتاح الذي أنشأته في القسم السابق.
في Xcode، افتح قسم التوقيع والإمكانات في محرِّر المشروع وأضِف إمكانية تسجيل الدخول باستخدام Apple.
سجِّل موفِّر الخدمة في مثيل
AuthService:let authService = AuthService() .withAppleSignIn()
لاستخدام ميزة "تسجيل الدخول باستخدام حساب Google"، اتّبِع الخطوات التالية:
من قسم الأمان > المصادقة > طريقة تسجيل الدخول في وحدة تحكّم Firebase، فعِّل مزوّد خدمة Google.
نزِّل نسخة جديدة من ملف
GoogleService-Info.plistالخاص بمشروعك وانسخها إلى مشروعك في Xcode. استبدِل أي إصدارات حالية بالإصدار الجديد.أضِف مخطّطات عناوين URL المخصّصة إلى مشروع Xcode:
افتح إعدادات مشروعك: انقر على اسم المشروع في العرض التدرّجي للحساب على يمين الصفحة. اختَر تطبيقك من قسم TARGETS (الأهداف)، ثم اختَر علامة التبويب Info (المعلومات)، ووسِّع قسم URL Types (أنواع عناوين URL).
انقر على الزر +، وأضِف مخطّط URL لمعرِّف العميل المعكوس. للعثور على هذه القيمة، افتح ملف الإعداد
وابحث عن المفتاحGoogleService-Info.plist REVERSED_CLIENT_ID. انسخ قيمة هذا المفتاح، وألصِقها في مربّع مخطّطات عناوين URL في صفحة الإعدادات. اترك الحقول الأخرى بدون تغيير.عند الانتهاء، من المفترض أن يظهر ملف الإعدادات على النحو التالي (ولكن مع القيم الخاصة بتطبيقك):
سجِّل موفِّر الخدمة في مثيل
AuthService:let authService = AuthService() .withGoogleSignIn()
لاستخدام ميزة "تسجيل الدخول باستخدام Facebook" (Facebook Login):
يمكنك إعداد حزمة تطوير البرامج (SDK) لميزة "تسجيل الدخول باستخدام Facebook" على أجهزة iOS باتّباع التعليمات على موقع Meta for Developers الإلكتروني. تخطَّ الخطوة الأخيرة، "إضافة تسجيل الدخول باستخدام Facebook إلى الرمز".
من قسم الأمان > المصادقة > طريقة تسجيل الدخول في وحدة تحكّم "Firebase"، فعِّل مزوّد خدمة Facebook. ستحتاج إلى رقم تعريف تطبيق Facebook والرمز السري للتطبيق من موقع Meta for Developers الإلكتروني.
سجِّل موفِّر الخدمة في مثيل
AuthService:let authService = AuthService() .withFacebookSignIn()
رقم الهاتف
لاستخدام المصادقة عبر الهاتف:
من قسم الأمان > المصادقة > طريقة تسجيل الدخول في وحدة تحكّم Firebase، فعِّل مزوّد خدمة الهاتف.
اضبط إعدادات APNs لتطبيقك كما هو موضّح في قسم بدء تلقّي الإشعارات الصامتة.
أضِف مخطّطات عناوين URL مخصّصة إلى مشروع Xcode:
افتح إعدادات مشروعك: انقر على اسم المشروع في العرض التدرّجي للحساب على يمين الصفحة. اختَر تطبيقك من قسم TARGETS (الأهداف)، ثم اختَر علامة التبويب Info (المعلومات)، ووسِّع قسم URL Types (أنواع عناوين URL).
انقر على الزر +، وأضِف معرّف التطبيق المشفَّر كمخطّط عنوان URL. للعثور على هذه القيمة، افتح الإعدادات > الإعدادات العامة في وحدة تحكّم "Firebase".
عند الانتهاء، من المفترض أن يظهر ملف الإعدادات على النحو التالي (ولكن مع القيم الخاصة بتطبيقك):
في
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 } }سجِّل موفِّر الخدمة في مثيل
AuthService:let authService = AuthService() .withPhoneSignIn()
Twitter (X)
لاستخدام ميزة "تسجيل الدخول باستخدام Twitter" (Twitter Login):
أنشِئ بيانات اعتماد واجهة برمجة تطبيقات X باتّباع التعليمات على موقع X Developers الإلكتروني.
من قسم الأمان > المصادقة > طريقة تسجيل الدخول في وحدة تحكّم Firebase، فعِّل مزوّد خدمة Twitter. ستحتاج إلى مفتاح واجهة برمجة التطبيقات وواجهة برمجة تطبيقات سرّية من وحدة تحكّم المطوّرين في X.
سجِّل موفِّر الخدمة في مثيل
AuthService:let authService = AuthService() .withTwitterSignIn()
موفّرو OAuth2 وOIDC العاديون
تتيح FirebaseUI أيضًا استخدام موفّري OAuth المدمجين، مثل GitHub وMicrosoft وYahoo، بالإضافة إلى موفّري OIDC المخصّصين الذين تم ضبطهم في "مصادقة Firebase".
let authService = AuthService()
.withOAuthSignIn(OAuthProviderSwift.github())
.withOAuthSignIn(OAuthProviderSwift.microsoft())
.withOAuthSignIn(OAuthProviderSwift.yahoo())
بالنسبة إلى موفّري OIDC المخصّصين، يجب ضبط الموفّر أولاً في "مصادقة Firebase"، ثم إنشاء 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)
استخدام طريقة عرض المصادقة المُعدّة مسبقًا
توفّر FirebaseUI لـ SwiftUI واجهة AuthPickerView، وهي واجهة مستخدم مصمَّمة مسبقًا ومخصَّصة للمصادقة، وتتولّى معالجة عملية المصادقة بالكامل نيابةً عنك. هذه هي أسهل طريقة لإضافة المصادقة إلى تطبيقك.
مثال
في ما يلي مثال على استخدام 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، يمكنك الحصول على:
- عرض ورقة البيانات: تظهر واجهة مستخدم المصادقة كورقة بيانات مشروطة
- التنقّل المضمّن: التنقّل التلقائي بين شاشات تسجيل الدخول واسترداد كلمة المرور والمصادقة المتعدّدة العوامل ورابط البريد الإلكتروني وتأكيد الحساب عبر الهاتف
- إدارة حالة المصادقة: يتم التبديل تلقائيًا بين واجهة مستخدم المصادقة والمحتوى استنادًا إلى
authService.authenticationState - التحكّم من خلال
isPresented: يمكنك التحكّم في وقت ظهور صفحة المصادقة من خلال ضبطauthService.isPresented = true/false
السلوكيات القائمة على الرأي الشخصي
يقدّم AuthPickerView التلقائي اقتراحات حول كيفية التعامل مع العديد من السيناريوهات المعقّدة:
1. حلّ تعارضات الحسابات
عند حدوث تعارض في الحساب (على سبيل المثال، تسجيل الدخول باستخدام بيانات اعتماد مرتبطة بحساب آخر)، يعالج AuthPickerView ذلك تلقائيًا:
- تعارضات الترقية المجهولة الهوية: في حال تفعيل
shouldAutoUpgradeAnonymousUsersوحدث تعارض أثناء الترقية المجهولة الهوية، يسجّل النظام خروج المستخدم المجهول الهوية تلقائيًا ويسجّل الدخول باستخدام بيانات الاعتماد الجديدة. - حالات التعارض الأخرى: في حال تعارض بيانات الاعتماد بين الحسابات غير المجهولة، يخزّن النظام بيانات الاعتماد المعلّقة ويحاول ربطها بعد تسجيل الدخول بنجاح.
ويتم التعامل مع ذلك من خلال AccountConflictModifier المطبَّق على مستوى NavigationStack.
2. المصادقة المتعدّدة العوامل (MFA)
عند تفعيل المصادقة المتعدّدة العوامل في الإعدادات:
- يرصد تلقائيًا الحالات التي تتطلّب استخدام المصادقة المتعدّدة العوامل أثناء تسجيل الدخول
- عرض شاشات حلول المصادقة المتعدّدة العوامل المناسبة (رسائل SMS أو كلمات المرور لمرة واحدة المستندة إلى الوقت)
- تتعامل مع عمليات التسجيل والإدارة في المصادقة المتعدّدة العوامل
- يتيح استخدام عوامل "كلمة المرور صالحة لمرة واحدة" المستندة إلى الرسائل القصيرة والمستندة إلى الوقت (TOTP)
3- معالجة الأخطاء
تتضمّن طرق العرض التلقائية معالجة الأخطاء المضمّنة:
- يعرض رسائل خطأ سهلة الاستخدام في مربّعات حوار التنبيهات
- تتم تلقائيًا فلترة الأخطاء التي تتم معالجتها داخليًا (مثل أخطاء الإلغاء والتعارضات التي تتم معالجتها تلقائيًا)
- يستخدم رسائل خطأ مترجَمة من خلال
StringUtils - يتم نشر الأخطاء من خلال مفتاح بيئة
reportError
4. تسجيل الدخول باستخدام رابط البريد الإلكتروني
عند ضبط ميزة تسجيل الدخول عبر رابط في رسالة إلكترونية:
- يتم تخزين عنوان البريد الإلكتروني تلقائيًا في مساحة تخزين التطبيق
- يتولّى التنقّل في الروابط لصفحات معيّنة من الرسائل الإلكترونية
- إدارة عملية تأكيد عنوان البريد الإلكتروني بالكامل
- يتيح ترقية المستخدمين المجهولي الهوية من خلال رابط في رسالة إلكترونية
5- الترقية التلقائية للمستخدمين المجهولي الهوية
عند تفعيل ميزة "shouldAutoUpgradeAnonymousUsers":
- محاولة ربط الحسابات المجهولة تلقائيًا ببيانات اعتماد تسجيل الدخول الجديدة
- يحافظ على بيانات المستخدم من خلال الترقية بدلاً من استبدال الجلسات المجهولة
- يتعامل مع تعارضات الترقية بسلاسة
6. إعادة المصادقة في طرق العرض التلقائية
تتطلّب العمليات الحسّاسة، مثل حذف الحسابات أو تعديل كلمات المرور أو إلغاء تسجيل عوامل المصادقة المتعدّدة العوامل، إجراء مصادقة حديثة. عند استخدام طرق العرض التلقائية، تتم معالجة إعادة المصادقة تلقائيًا استنادًا إلى موفّر خدمة تسجيل الدخول للمستخدم.
عندما تتطلّب عملية حسّاسة إعادة المصادقة، يتم تلقائيًا عرض ما يلي:
مقدّمو خدمات OAuth (مثل Google وApple وFacebook وTwitter): عرض تنبيه يطلب من المستخدم التأكيد، ثم الحصول تلقائيًا على بيانات اعتماد جديدة وإكمال العملية
البريد الإلكتروني/كلمة المرور: يتم عرض صفحة تطلب من المستخدم إدخال كلمة المرور قبل المتابعة.
رابط البريد الإلكتروني: يعرض هذا الخيار تنبيهًا يطلب إرسال رسالة تأكيد، ثم يعرض ورقة تتضمّن تعليمات للتحقّق من البريد الإلكتروني. ينقر المستخدم على الرابط في رسالته الإلكترونية لإكمال عملية إعادة المصادقة.
الهاتف: يتم عرض تنبيه يشرح الحاجة إلى إثبات الهوية، ثم تظهر صفحة لإثبات الهوية باستخدام رمز SMS.
تتم إعادة محاولة تنفيذ العملية تلقائيًا بعد إعادة المصادقة بنجاح. لا يلزم استخدام رمز إضافي عند استخدام AuthPickerView أو طرق عرض إدارة الحساب المضمّنة (UpdatePasswordView وSignedInView وما إلى ذلك).
إعداد متقدّم: إنشاء طرق عرض مخصّصة للمصادقة
إذا كنت بحاجة إلى مزيد من التحكّم في واجهة المستخدم أو مسار التنقّل، يمكنك إنشاء طرق عرض مخصّصة للمصادقة مع الاستفادة من AuthService في منطق المصادقة.
يمكنك مزج عناصر FirebaseUI مع المنطق المخصّص بعدة طرق. تحتوي الأقسام التالية على أمثلة لبعض أساليب التخصيص التي قد تستخدمها.
النهج 1: أزرار مخصّصة باستخدام registerProvider()
للتحكّم بشكل كامل في مظهر الزر، يمكنك إنشاء عملية تنفيذ مخصّصة لـ AuthProviderUI تلتف حول أي مقدّم خدمة وتعرض طريقة عرض الزر المخصّصة.
إنشاء واجهة مستخدم مخصّصة لمقدّم الخدمة
في ما يلي كيفية إنشاء زر 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 وPhone ومقدّمي خدمات OAuth. ما عليك سوى إنشاء طريقة عرض الزر المخصّص وتضمينها في فئة تتوافق مع AuthProviderUI.
النهج 2: الأزرار التلقائية مع طرق العرض المخصّصة
يمكنك استخدام 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 تلقائيًا:
- تعارضات الحسابات: يمكنك تنفيذ استراتيجيتك الخاصة لحلّ التعارضات باستخدام
AuthServiceError.accountConflict - معالجة المصادقة المتعدّدة العوامل (MFA): يُرجى التحقّق من
SignInOutcomeبحثًا عن.mfaRequiredومعالجة حلّ المصادقة المتعدّدة العوامل يدويًا - ترقيات المستخدمين مجهولي الهوية: يمكنك إدارة ربط الحسابات مجهولة الهوية في حال تفعيل ميزة "
shouldAutoUpgradeAnonymousUsers" - حالة التنقّل: يمكنك إدارة التنقّل بين شاشات المصادقة المختلفة (تأكيد الحساب عبر الهاتف، واسترداد كلمة المرور، وما إلى ذلك).
- حالات التحميل: يمكنك عرض مؤشرات التحميل أثناء عمليات المصادقة غير المتزامنة من خلال مراقبة
authService.authenticationState - إعادة المصادقة: معالجة أخطاء إعادة المصادقة للعمليات الحسّاسة (يُرجى الاطّلاع على إعادة المصادقة في طرق العرض المخصّصة أدناه)
إعادة المصادقة في طرق العرض المخصّصة
عند إنشاء طرق عرض مخصّصة، يمكنك معالجة إعادة المصادقة من خلال رصد أخطاء معيّنة وتنفيذ المسار الخاص بك. تؤدي العمليات الحسّاسة إلى ظهور أربعة أنواع من أخطاء إعادة المصادقة، ويحتوي كلّ منها على معلومات السياق.
أنماط التنفيذ
مقدّمو خدمات 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) في إعدادات المصادقة في مشروع Firebase قبل استخدامهم. في وحدة تحكُّم Firebase، انتقِل إلى المصادقة ← طريقة تسجيل الدخول وأضِف موفِّر OIDC مع بيانات الاعتماد المطلوبة (معرِّف العميل وسر العميل وعنوان URL الخاص بجهة الإصدار). يجب أيضًا تسجيل معرّف الموارد المنتظم (URI) لإعادة التوجيه عبر OAuth الذي يوفّره Firebase في وحدة تحكّم المطوّرين لدى الموفّر. يمكنك الاطّلاع على مستندات 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)
}
}