1. قبل البدء
يرشدك هذا الدرس التطبيقي حول الترميز إلى كيفية إنشاء تطبيق iOS يستخدم ميزة "تسجيل الدخول باستخدام حساب Google" ويعمل في محاكي. يتم توفير عمليات تنفيذ تستخدم كلاً من SwiftUI وUIKit.
SwiftUI هو إطار عمل حديث لواجهة المستخدم من Apple لتطوير التطبيقات الجديدة. تتيح هذه الأداة إنشاء واجهات مستخدم لجميع منصات Apple من قاعدة رموز برمجية مشتركة واحدة. يتطلّب الإصدار 13 من نظام التشغيل iOS كحد أدنى.
UIKit هو إطار عمل واجهة المستخدم الأصلي والأساسي من Apple لنظام التشغيل iOS. ويوفّر توافقًا مع الإصدارات القديمة من نظام التشغيل iOS. وهذا يجعلها خيارًا جيدًا للتطبيقات المعروفة التي تحتاج إلى التوافق مع مجموعة متنوعة من الأجهزة القديمة.
يمكنك اتّباع مسار إطار العمل الذي يتوافق بشكل أفضل مع احتياجاتك المتعلقة بالتطوير.
المتطلبات الأساسية
أهداف الدورة التعليمية
- كيفية إنشاء مشروع على Google Cloud
- كيفية إنشاء برامج تعتمد على بروتوكول OAuth في Google Cloud Console
- كيفية تنفيذ ميزة "تسجيل الدخول باستخدام حساب Google" لتطبيق iOS
- كيفية تخصيص زر "تسجيل الدخول باستخدام حساب Google"
- كيفية فك ترميز رمز التعريف
- كيفية تفعيل خدمة App Check لتطبيق iOS
المتطلبات
- إصدار حالي من Xcode
- جهاز كمبيوتر يعمل بنظام التشغيل macOS يستوفي متطلبات النظام لإصدار Xcode الذي ثبّته
تم إنشاء هذا الدرس التطبيقي حول الترميز باستخدام Xcode 16.3 مع محاكي iOS 18.3. يجب استخدام أحدث إصدار من Xcode للتطوير.
2. إنشاء مشروع Xcode جديد
- افتح Xcode وانقر على Create a new Xcode project (إنشاء مشروع Xcode جديد).
- اختَر علامة التبويب iOS، ثم اختَر نموذج التطبيق، وانقر على التالي.

- في خيارات المشروع:
- أدخِل اسم المنتج.
- اختَر الفريق بشكل اختياري.
- أدخِل معرّف المؤسسة.
- دوِّن معرّف الحزمة الذي تم إنشاؤه. ستحتاج إليه لاحقًا.
- بالنسبة إلى الواجهة، اختَر أحد الخيارَين التاليَين:
- SwiftUI لتطبيق يستند إلى SwiftUI
- مخطط القصة لتطبيق يستند إلى UIKit
- اختَر Swift في اللغة.
- انقر على التالي واختَر موقعًا جغرافيًا لحفظ مشروعك.

3- إنشاء عميل OAuth
للسماح لتطبيقك بالتواصل مع خدمات المصادقة من Google، عليك إنشاء معرّف عميل OAuth. يتطلّب ذلك مشروعًا على Google Cloud. ستساعدك الخطوات التالية في عملية إنشاء مشروع ومعرّف عميل OAuth.
اختيار مشروع Google Cloud أو إنشاؤه
- انتقِل إلى Google Cloud Console واختَر مشروعًا أو أنشِئ مشروعًا. في حال اختيار مشروع حالي، ستوجّهك وحدة التحكّم تلقائيًا إلى الخطوة التالية المطلوبة.

- أدخِل اسمًا لمشروعك الجديد على Google Cloud.
- انقر على إنشاء.

ضبط شاشة الموافقة
إذا سبق لك ضبط شاشة طلب الموافقة للمشروع المحدّد، لن يُطلب منك ضبطها الآن. في هذه الحالة، يمكنك تخطّي هذا القسم والانتقال إلى إنشاء عميل OAuth 2.0.
- انقر على إعداد شاشة الموافقة.

- انقر على البدء في صفحة "وضع العلامة التجارية".

- في صفحة إعدادات المشروع، املأ الحقول التالية:
- معلومات التطبيق: أدخِل اسمًا وبريدًا إلكترونيًا لدعم المستخدمين في تطبيقك. سيتم عرض عنوان البريد الإلكتروني هذا بشكل علني ليتمكّن المستخدمون من التواصل معك لطرح أسئلة حول موافقتهم.
- الجمهور: اختَر خارجي.
- معلومات الاتصال: أدخِل عنوان بريد إلكتروني لكي تتمكّن Google من التواصل معك بشأن مشروعك.
- راجِع خدمات Google API: سياسة بيانات المستخدمين.
- انقر على إنشاء.

- اختَر صفحة العملاء في قائمة التنقّل.
- انقر على إنشاء عميل.

إنشاء عميل OAuth 2.0
- اختَر iOS في حقل نوع التطبيق.
- أدخِل اسمًا لعميلك.
- أدخِل معرّف الحزمة الذي تم إنشاؤه في الخطوة الأخيرة.
- أدخِل معرّف الفريق الذي خصّصته Apple لفريقك. هذه الخطوة اختيارية في الوقت الحالي، ولكن يجب توفير معرّف فريق لتفعيل App Check لاحقًا في هذا الدرس العملي.
- انقر على إنشاء.

- انسخ معرّف العميل من نافذة الحوار، وستحتاج إليه لاحقًا.
- نزِّل ملف plist للرجوع إليه لاحقًا.

4. إعداد مشروع Xcode
الخطوة التالية هي إعداد مشروع Xcode للعمل مع حزمة تطوير البرامج (SDK) الخاصة بخدمة "تسجيل الدخول باستخدام Google". تتضمّن هذه العملية إضافة حزمة SDK إلى مشروعك كعنصر تابع وتعديل إعدادات مشروعك باستخدام معرّف عميل فريد. يسمح هذا المعرّف لحزمة SDK بالتواصل بأمان مع خدمة المصادقة من Google أثناء عملية تسجيل الدخول.
تثبيت التبعيات الخاصة بميزة "تسجيل الدخول باستخدام حساب Google"
- افتح مشروع Xcode.
- انتقِل إلى ملف (File) > إضافة تبعيات الحزمة (Add Package Dependencies).
- في شريط البحث، أدخِل عنوان URL لمستودع "تسجيل الدخول باستخدام Google": https://github.com/google/GoogleSignIn-iOS

- انقر على إضافة حزمة.
- اختَر هدف التطبيق الرئيسي لحزمة GoogleSignIn.
- إذا كنت تستخدم SwiftUI، اختَر هدف التطبيق الرئيسي لحزمة GoogleSignInSwift. إذا كنت تخطّط لاستخدام UIKit، لا تحدّد هدفًا لهذه الحزمة.
- انقر على إضافة حزمة.

ضبط بيانات اعتماد تطبيقك
- في "مستكشف المشروع" (Project Navigator)، انقر على جذر مشروعك.
- في منطقة المحرّر الرئيسية، اختَر هدف تطبيقك الرئيسي من قائمة الأهداف.
- انقر على علامة التبويب معلومات في أعلى مساحة المحرّر.
- مرِّر مؤشر الماوس فوق الصف الأخير في قسم خصائص استهداف iOS المخصّصة وانقر على الزر + الذي يظهر.

- في عمود المفتاح، اكتب GIDClientID.
- في عمود القيمة، ألصِق معرّف العميل الذي نسخته من Google Cloud Console.

- افتح ملف plist الذي نزّلته من Google Cloud Console.
- انسخ قيمة معرّف العميل المعكوس.

- وسِّع أنواع عناوين URL في أسفل علامة التبويب المعلومات.
- انقر على الزر +.
- أدخِل معرّف العميل المعكوس في المربّع مخططات عناوين URL.

نحن الآن جاهزون لبدء إضافة زر تسجيل الدخول إلى تطبيقنا.
5- إضافة زر تسجيل الدخول
بعد إعداد مشروع Xcode، حان الوقت لبدء إضافة زر "تسجيل الدخول باستخدام حساب Google" إلى التطبيق.
المنطق الأساسي لهذه الخطوة هو استدعاء GIDSignIn.sharedInstance.signIn. تبدأ هذه الطريقة عملية المصادقة، وتمنح التحكّم في واجهة برمجة التطبيقات Sign in with Google SDK لعرض عملية "تسجيل الدخول باستخدام حساب Google" للمستخدم.
SwiftUI
- ابحث عن الملف ContentView.swift في "مستكشف المشروع" (Project Navigator) في Xcode.
- استبدِل محتوى هذا الملف بالنص التالي:
import GoogleSignIn
import GoogleSignInSwift
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
GoogleSignInButton(action: handleSignInButton).padding()
}
}
func handleSignInButton() {
// Find the current window scene.
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else {
print("There is no active window scene")
return
}
// Get the root view controller from the window scene.
guard
let rootViewController = windowScene.windows.first(where: { $0.isKeyWindow })?
.rootViewController
else {
print("There is no key window or root view controller")
return
}
// Start the sign-in process.
GIDSignIn.sharedInstance.signIn(
withPresenting: rootViewController
) { signInResult, error in
guard let result = signInResult else {
// Inspect error
print("Error signing in: \(error?.localizedDescription ?? "No error description")")
return
}
// If sign in succeeded, display the app's main content View.
print("ID Token: \(result.user.idToken?.tokenString ?? "")")
}
}
}
#Preview {
ContentView()
}

UIKit
- ابحث عن الملف ViewController.swift في "مستكشف المشروع" (Project Navigator) في Xcode.
- استبدِل محتوى هذا الملف بالنص التالي:
import GoogleSignIn
import UIKit
class ViewController: UIViewController {
// Create an instance of the Sign in with Google button
let signInButton = GIDSignInButton()
override func viewDidLoad() {
super.viewDidLoad()
// Add the sign-in button to your view
view.addSubview(signInButton)
// Position the button using constraints
signInButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
signInButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
signInButton.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
// Add a target to the button to call a method when it's pressed
signInButton.addTarget(self, action: #selector(signInButtonTapped), for: .touchUpInside)
}
// This method is called when the sign-in button is pressed.
@objc func signInButtonTapped() {
// Start the sign-in process.
GIDSignIn.sharedInstance.signIn(withPresenting: self) { signInResult, error in
guard let result = signInResult else {
// Inspect error
print("Error signing in: \(error?.localizedDescription ?? "No error description")")
return
}
// If sign in succeeded, print the ID token.
print("ID Token: \(result.user.idToken?.tokenString ?? "")")
}
}
}

عرض زر تسجيل الدخول
شغِّل تطبيقك في المحاكي. سيظهر لك الزر "تسجيل الدخول باستخدام حساب Google"، ولكنّه لن يعمل بشكل صحيح بعد. وهذا أمر متوقّع، إذ لا يزال عليك تنفيذ الرمز البرمجي للتعامل مع إعادة التوجيه إلى تطبيقك بعد مصادقة المستخدم.
6. تخصيص زر تسجيل الدخول
يمكنك تخصيص زر "تسجيل الدخول باستخدام Google" التلقائي ليتناسب بشكل أفضل مع مظهر تطبيقك. تتيح لك حزمة تطوير البرامج (SDK) الخاصة بخدمة "تسجيل الدخول باستخدام حساب Google" تعديل نظام الألوان ونمط الزر.
SwiftUI
تتم إضافة الزر التلقائي إلى الصفحة باستخدام سطر الرمز التالي:
GoogleSignInButton(action: handleSignInButton)
يتم تخصيص GoogleSignInButton من خلال تمرير المَعلمات إلى أداة التهيئة. سيؤدي الرمز التالي إلى عرض زر تسجيل الدخول في الوضع الداكن.
- افتح ContentView.swift
- عدِّل أداة التهيئة الخاصة بـ
GoogleSignInButtonلتتضمّن القيم التالية:
GoogleSignInButton(
scheme: .dark, // Options: .light, .dark, .auto
style: .standard, // Options: .standard, .wide, .icon
state: .normal, // Options: .normal, .disabled
action: handleSignInButton
).padding()

لمزيد من المعلومات عن خيارات التخصيص، يُرجى الاطّلاع على مرجع إطار عمل GoogleSignInSwift.
UIKit
يتم إنشاء الزر التلقائي باستخدام أسطر الرمز البرمجي التالية:
// Create an instance of the Sign in with Google button
let signInButton = GIDSignInButton()
// Add the button to your view
view.addSubview(signInButton)
يتم تخصيص GIDSignInButton من خلال ضبط الخصائص على مثيل الزر. سيؤدي الرمز التالي إلى عرض زر تسجيل الدخول في الوضع الداكن.
- افتح ViewController.swift.
- أضِف أسطر الرمز البرمجي التالية قبل إضافة زر تسجيل الدخول إلى طريقة العرض في الدالة
viewDidLoad:
// Set the width and color of the sign-in button
signInButton.style = .standard // Options: .standard, .wide, .iconOnly
signInButton.colorScheme = .dark // Options: .dark, .light

لمزيد من المعلومات حول التخصيص، اطّلِع على مرجع إطار عمل GoogleSignIn.
7. التعامل مع عنوان URL لإعادة التوجيه الخاص بالمصادقة
بعد إضافة زر تسجيل الدخول، تتمثّل الخطوة التالية في التعامل مع عملية إعادة التوجيه التي تحدث بعد مصادقة المستخدم. بعد المصادقة، تعرض Google عنوان URL يتضمّن رمز تفويض مؤقتًا. لإكمال عملية تسجيل الدخول، يعترض معالج عنوان URL هذا ويمرّره إلى حزمة تطوير البرامج (SDK) الخاصة بخدمة "تسجيل الدخول باستخدام حساب Google" ليتم استبداله برمز مميّز معرّف موقَّع (JWT).
SwiftUI
- افتح الملف الذي يحتوي على بنية
App. يتم تسمية هذا الملف استنادًا إلى مشروعك، لذا سيكون الاسم على النحو التالي: YourProjectNameApp.swift. - استبدِل محتوى هذا الملف بالنص التالي:
import GoogleSignIn
import SwiftUI
@main
struct iOS_Sign_in_with_Google_App: App {
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL { url in
GIDSignIn.sharedInstance.handle(url)
}
}
}
}
UIKit
- افتح الملف AppDelegate.swift.
- أضِف عملية الاستيراد التالية إلى أعلى الملف:
import GoogleSignIn
- أضِف دالة معالج المصادقة التالية داخل الفئة
AppDelegate. يمكنك وضعها مباشرةً بعد القوس المعقوف الأخير الخاص بالطريقةapplication(_:didFinishLaunchingWithOptions:):
func application(
_ app: UIApplication,
open url: URL,
options: [UIApplication.OpenURLOptionsKey: Any] = [:]
) -> Bool {
var handled: Bool
handled = GIDSignIn.sharedInstance.handle(url)
if handled {
return true
}
// If not handled by this app, return false.
return false
}
بعد إجراء هذه التغييرات، من المفترض أن يبدو ملف AppDelegate.swift على النحو التالي:
import GoogleSignIn
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Override point for customization after application launch.
return true
}
func application(
_ app: UIApplication,
open url: URL,
options: [UIApplication.OpenURLOptionsKey: Any] = [:]
) -> Bool {
var handled: Bool
handled = GIDSignIn.sharedInstance.handle(url)
if handled {
return true
}
// If not handled by this app, return false.
return false
}
// MARK: UISceneSession Lifecycle
func application(
_ application: UIApplication,
configurationForConnecting connectingSceneSession: UISceneSession,
options: UIScene.ConnectionOptions
) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(
name: "Default Configuration",
sessionRole: connectingSceneSession.role
)
}
func application(
_ application: UIApplication,
didDiscardSceneSessions sceneSessions: Set<UISceneSession>
) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
}
اختبار خطوات تسجيل الدخول
يمكنك الآن اختبار عملية تسجيل الدخول الكاملة.
شغِّل تطبيقك وانقر على زر تسجيل الدخول. بعد إثبات هويتك، ستعرض Google شاشة موافقة يمكنك من خلالها منح التطبيق الإذن بالوصول إلى معلوماتك. بعد الموافقة، سيتم إكمال عملية تسجيل الدخول، وستتم إعادتك إلى التطبيق.
عند اكتمال عملية تسجيل الدخول بنجاح، يخزِّن حزمة تطوير البرامج (SDK) الخاصة بميزة "تسجيل الدخول باستخدام حساب Google" بيانات اعتماد المستخدم بشكل آمن في Keychain على الجهاز. ويمكن استخدام بيانات الاعتماد هذه لاحقًا للسماح للمستخدم بالبقاء مسجّلاً الدخول عند تشغيل التطبيق في المرات اللاحقة.
8. إضافة زر تسجيل الخروج
بعد أن أصبح تسجيل الدخول متاحًا، الخطوة التالية هي إضافة زر تسجيل الخروج وتعديل واجهة المستخدم لتعكس حالة تسجيل الدخول الحالية للمستخدم. عند نجاح عملية تسجيل الدخول، توفّر حزمة SDK عنصر GIDGoogleUser. يحتوي هذا العنصر على السمة profile التي تتضمّن معلومات أساسية، مثل اسم المستخدم وعنوان بريده الإلكتروني، والتي ستستخدمها لتخصيص واجهة المستخدم.
SwiftUI
- افتح ملف ContentView.swift.
- أضِف متغيّر حالة في أعلى بنية
ContentView. سيحتوي هذا المتغيّر على معلومات المستخدم بعد تسجيل الدخول. بما أنّها متغيّر@State، ستعدّل SwiftUI واجهة المستخدم تلقائيًا كلما تغيّرت قيمتها:
struct ContentView: View {
@State private var user: GIDGoogleUser?
}
- استبدِل
bodyالحالي في بنيةContentViewبما يلي:VStack. سيتحقّق هذا الرمز مما إذا كان متغيّر الحالةuserيتضمّن مستخدمًا. في حال توفّرها، ستظهر رسالة ترحيب وزر تسجيل الخروج. إذا لم يكن كذلك، سيظهر زر "تسجيل الدخول باستخدام حساب Google" الأصلي:
var body: some View {
VStack {
// Check if the user is signed in.
if let user = user {
// If signed in, show a welcome message and the sign-out button.
Text("Hello, \(user.profile?.givenName ?? "User")!")
.font(.title)
.padding()
Button("Sign Out", action: signOut)
.buttonStyle(.borderedProminent)
} else {
// If not signed in, show the "Sign in with Google" button.
GoogleSignInButton(
scheme: .dark, // Options: .light, .dark, .auto
style: .standard, // Options: .standard, .wide, .icon
state: .normal, // Options: .normal, .disabled
action: handleSignInButton
).padding()
}
}
}
- عدِّل كتلة الإكمال
handleSignInButtonلتعيينsignInResult.userإلى المتغيّر الجديدuser. إليك ما يؤدي إلى تبديل واجهة المستخدم إلى العرض الخاص بالمستخدمين الذين سجّلوا الدخول:
func handleSignInButton() {
// Find the current window scene.
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else {
print("There is no active window scene")
return
}
// Get the root view controller from the window scene.
guard
let rootViewController = windowScene.windows.first(where: { $0.isKeyWindow })?
.rootViewController
else {
print("There is no key window or root view controller")
return
}
// Start the sign-in process.
GIDSignIn.sharedInstance.signIn(
withPresenting: rootViewController
) { signInResult, error in
guard let result = signInResult else {
// Inspect error
print("Error signing in: \(error?.localizedDescription ?? "No error description")")
return
}
DispatchQueue.main.async {
self.user = result.user
}
// If sign in succeeded, display the app's main content View.
print("ID Token: \(result.user.idToken?.tokenString ?? "")")
}
}
- أضِف دالة
signOutجديدة إلى أسفل بنيةContentViewليتم استدعاؤها من خلال زر تسجيل الخروج:
func signOut() {
GIDSignIn.sharedInstance.signOut()
// After signing out, set the `user` state variable to `nil`.
self.user = nil
}
افتح التطبيق وسجِّل الدخول. من المفترض أن تتغيّر واجهة المستخدم بعد إتمام عملية المصادقة بنجاح.

بعد إجراء هذه التغييرات، من المفترض أن يبدو ملف ContentView.swift على النحو التالي:
import GoogleSignIn
import GoogleSignInSwift
import SwiftUI
struct ContentView: View {
@State private var user: GIDGoogleUser?
var body: some View {
VStack {
// Check if the user is signed in.
if let user = user {
// If signed in, show a welcome message and the sign-out button.
Text("Hello, \(user.profile?.givenName ?? "User")!")
.font(.title)
.padding()
Button("Sign Out", action: signOut)
.buttonStyle(.borderedProminent)
} else {
// If not signed in, show the "Sign in with Google" button.
GoogleSignInButton(
scheme: .dark, // Options: .light, .dark, .auto
style: .standard, // Options: .standard, .wide, .icon
state: .normal, // Options: .normal, .disabled
action: handleSignInButton
).padding()
}
}
}
func handleSignInButton() {
// Find the current window scene.
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else {
print("There is no active window scene")
return
}
// Get the root view controller from the window scene.
guard
let rootViewController = windowScene.windows.first(where: { $0.isKeyWindow })?
.rootViewController
else {
print("There is no key window or root view controller")
return
}
// Start the sign-in process.
GIDSignIn.sharedInstance.signIn(
withPresenting: rootViewController
) { signInResult, error in
guard let result = signInResult else {
// Inspect error
print("Error signing in: \(error?.localizedDescription ?? "No error description")")
return
}
DispatchQueue.main.async {
self.user = result.user
}
// If sign in succeeded, display the app's main content View.
print("ID Token: \(result.user.idToken?.tokenString ?? "")")
}
}
func signOut() {
GIDSignIn.sharedInstance.signOut()
// After signing out, set the `user` state variable to `nil`.
self.user = nil
}
}
#Preview {
ContentView()
}
UIKit
- افتح ViewController.swift.
- في أعلى
ViewController، أسفل المكان الذي حدّدت فيهsignInButtonمباشرةً، أضِف زر تسجيل الخروج وتصنيف الترحيب:
let signOutButton = UIButton(type: .system)
let welcomeLabel = UILabel()
- أضِف الدالة التالية إلى أسفل
ViewController. ستعرض هذه الدالة واجهة مستخدم مختلفة للمستخدم استنادًا إلى حالة تسجيل الدخول:
private func updateUI(for user: GIDGoogleUser?) {
if let user = user {
// User is signed in.
signInButton.isHidden = true
signOutButton.isHidden = false
welcomeLabel.isHidden = false
welcomeLabel.text = "Hello, \(user.profile?.givenName ?? "User")!"
} else {
// User is signed out.
signInButton.isHidden = false
signOutButton.isHidden = true
welcomeLabel.isHidden = true
}
}
- في أسفل الدالة
viewDidLoad، أضِف الرمز التالي لإضافة تصنيف الترحيب وزر تسجيل الخروج إلى العرض:
// --- Set up the Welcome Label ---
welcomeLabel.translatesAutoresizingMaskIntoConstraints = false
welcomeLabel.textAlignment = .center
welcomeLabel.font = .systemFont(ofSize: 24, weight: .bold)
view.addSubview(welcomeLabel)
NSLayoutConstraint.activate([
welcomeLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
welcomeLabel.bottomAnchor.constraint(equalTo: signInButton.topAnchor, constant: -20),
])
// --- Set up the Sign-Out Button ---
signOutButton.translatesAutoresizingMaskIntoConstraints = false
signOutButton.setTitle("Sign Out", for: .normal)
view.addSubview(signOutButton)
NSLayoutConstraint.activate([
signOutButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
signOutButton.topAnchor.constraint(equalTo: signInButton.bottomAnchor, constant: 20),
])
signOutButton.addTarget(self, action: #selector(signOutButtonTapped), for: .touchUpInside)
// --- Set Initial UI State ---
updateUI(for: nil)
- عدِّل الدالة
signInButtonTappedلاستدعاء الطريقةUpdateUIعند تسجيل الدخول بنجاح:
@objc func signInButtonTapped() {
// Start the sign-in process.
GIDSignIn.sharedInstance.signIn(withPresenting: self) { signInResult, error in
guard let result = signInResult else {
// Inspect error
print("Error signing in: \(error?.localizedDescription ?? "No error description")")
return
}
// If sign in succeeded, print the ID token.
print("ID Token: \(result.user.idToken?.tokenString ?? "")")
DispatchQueue.main.async {
self.updateUI(for: result.user)
}
}
}
- أخيرًا، أضِف الدالة
signOutButtonTappedإلىViewControllerللتعامل مع عملية تسجيل الخروج:
@objc func signOutButtonTapped() {
GIDSignIn.sharedInstance.signOut()
// Update the UI for the signed-out state.
updateUI(for: nil)
}
افتح التطبيق وسجِّل الدخول. من المفترض أن تتغيّر واجهة المستخدم بعد إتمام عملية المصادقة بنجاح.

بعد إجراء هذه التغييرات، من المفترض أن يبدو ملف ViewController.swift كما يلي:
import GoogleSignIn
import UIKit
class ViewController: UIViewController {
// Create an instance of the Sign in with Google button
let signInButton = GIDSignInButton()
let signOutButton = UIButton(type: .system)
let welcomeLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
// Set the width and color of the sign-in button
signInButton.style = .standard // Options: .standard, .wide, .iconOnly
signInButton.colorScheme = .dark // Options: .dark, .light
// Add the sign-in button to your view
view.addSubview(signInButton)
// Position the button using constraints
signInButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
signInButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
signInButton.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
// Add a target to the button to call a method when it's pressed
signInButton.addTarget(self, action: #selector(signInButtonTapped), for: .touchUpInside)
// --- Set up the Welcome Label ---
welcomeLabel.translatesAutoresizingMaskIntoConstraints = false
welcomeLabel.textAlignment = .center
welcomeLabel.font = .systemFont(ofSize: 24, weight: .bold)
view.addSubview(welcomeLabel)
NSLayoutConstraint.activate([
welcomeLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
welcomeLabel.bottomAnchor.constraint(equalTo: signInButton.topAnchor, constant: -20),
])
// --- Set up the Sign-Out Button ---
signOutButton.translatesAutoresizingMaskIntoConstraints = false
signOutButton.setTitle("Sign Out", for: .normal)
view.addSubview(signOutButton)
NSLayoutConstraint.activate([
signOutButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
signOutButton.topAnchor.constraint(equalTo: signInButton.bottomAnchor, constant: 20),
])
signOutButton.addTarget(self, action: #selector(signOutButtonTapped), for: .touchUpInside)
// --- Set Initial UI State ---
updateUI(for: nil)
}
// This method is called when the sign-in button is pressed.
@objc func signInButtonTapped() {
// Start the sign-in process.
GIDSignIn.sharedInstance.signIn(withPresenting: self) { signInResult, error in
guard let result = signInResult else {
// Inspect error
print("Error signing in: \(error?.localizedDescription ?? "No error description")")
return
}
// If sign in succeeded, print the ID token.
print("ID Token: \(result.user.idToken?.tokenString ?? "")")
DispatchQueue.main.async {
self.updateUI(for: result.user)
}
}
}
private func updateUI(for user: GIDGoogleUser?) {
if let user = user {
// User is signed in.
signInButton.isHidden = true
signOutButton.isHidden = false
welcomeLabel.isHidden = false
welcomeLabel.text = "Hello, \(user.profile?.givenName ?? "User")!"
} else {
// User is signed out.
signInButton.isHidden = false
signOutButton.isHidden = true
welcomeLabel.isHidden = true
}
}
@objc func signOutButtonTapped() {
GIDSignIn.sharedInstance.signOut()
// Update the UI for the signed-out state.
updateUI(for: nil)
}
}
9- استعادة حالة تسجيل دخول المستخدم
لتحسين تجربة المستخدمين العائدين، تتمثّل الخطوة التالية في استعادة حالة تسجيل الدخول عند تشغيل التطبيق. تستخدم ميزة "الاتصال" (Calling) restorePreviousSignIn بيانات الاعتماد المحفوظة في Keychain لإعادة تسجيل دخول المستخدم بدون الحاجة إلى إكمال خطوات تسجيل الدخول في كل مرة.
SwiftUI
- افتح الملف ContentView.swift.
- أضِف الرمز التالي مباشرةً بعد
VStackداخل المتغيّرbody:
.onAppear {
// On appear, try to restore a previous sign-in.
GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in
// This closure is called when the restoration is complete.
if let user = user {
// If a user was restored, update the `user` state variable.
DispatchQueue.main.async {
self.user = user
}
// Print the ID token to the console when restored.
print("Restored ID Token: \(user.idToken?.tokenString ?? "")")
}
}
}
يجب أن يبدو ملف ContentView.swift على النحو التالي:
import GoogleSignIn
import GoogleSignInSwift
import SwiftUI
struct ContentView: View {
@State private var user: GIDGoogleUser?
var body: some View {
VStack {
// Check if the user is signed in.
if let user = user {
// If signed in, show a welcome message and the sign-out button.
Text("Hello, \(user.profile?.givenName ?? "User")!")
.font(.title)
.padding()
Button("Sign Out", action: signOut)
.buttonStyle(.borderedProminent)
} else {
// If not signed in, show the "Sign in with Google" button.
GoogleSignInButton(
scheme: .dark, // Options: .light, .dark, .auto
style: .standard, // Options: .standard, .wide, .icon
state: .normal, // Options: .normal, .disabled
action: handleSignInButton
).padding()
}
}
.onAppear {
// On appear, try to restore a previous sign-in.
GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in
// This closure is called when the restoration is complete.
if let user = user {
// If a user was restored, update the `user` state variable.
DispatchQueue.main.async {
self.user = user
}
// Print the ID token to the console when restored.
print("Restored ID Token: \(user.idToken?.tokenString ?? "")")
}
}
}
}
func handleSignInButton() {
// Find the current window scene.
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else {
print("There is no active window scene")
return
}
// Get the root view controller from the window scene.
guard
let rootViewController = windowScene.windows.first(where: { $0.isKeyWindow })?
.rootViewController
else {
print("There is no key window or root view controller")
return
}
// Start the sign-in process.
GIDSignIn.sharedInstance.signIn(
withPresenting: rootViewController
) { signInResult, error in
guard let result = signInResult else {
// Inspect error
print("Error signing in: \(error?.localizedDescription ?? "No error description")")
return
}
DispatchQueue.main.async {
self.user = result.user
}
// If sign in succeeded, display the app's main content View.
print("ID Token: \(result.user.idToken?.tokenString ?? "")")
}
}
func signOut() {
GIDSignIn.sharedInstance.signOut()
// After signing out, set the `user` state variable to `nil`.
self.user = nil
}
}
#Preview {
ContentView()
}
UIKit
- افتح ViewController.swift.
- أضِف استدعاء
restorePreviousSignInالتالي إلى نهاية طريقةviewDidLoad:
// Attempt to restore a previous sign-in session
GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in
if let user = user {
print("Successfully restored sign-in for user: \(user.profile?.givenName ?? "Unknown")")
// Print the ID token when a session is restored.
print("Restored ID Token: \(user.idToken?.tokenString ?? "")")
// On success, update the UI for the signed-in state on the main thread.
DispatchQueue.main.async {
self.updateUI(for: user)
}
}
}
يجب أن يبدو ملف ViewController.swift على النحو التالي:
import GoogleSignIn
import UIKit
class ViewController: UIViewController {
// Create an instance of the Sign in with Google button
let signInButton = GIDSignInButton()
let signOutButton = UIButton(type: .system)
let welcomeLabel = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
// Set the width and color of the sign-in button
signInButton.style = .standard // Options: .standard, .wide, .iconOnly
signInButton.colorScheme = .dark // Options: .dark, .light
// Add the sign-in button to your view
view.addSubview(signInButton)
// Position the button using constraints
signInButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
signInButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
signInButton.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
// Add a target to the button to call a method when it's pressed
signInButton.addTarget(self, action: #selector(signInButtonTapped), for: .touchUpInside)
// --- Set up the Welcome Label ---
welcomeLabel.translatesAutoresizingMaskIntoConstraints = false
welcomeLabel.textAlignment = .center
welcomeLabel.font = .systemFont(ofSize: 24, weight: .bold)
view.addSubview(welcomeLabel)
NSLayoutConstraint.activate([
welcomeLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
welcomeLabel.bottomAnchor.constraint(equalTo: signInButton.topAnchor, constant: -20),
])
// --- Set up the Sign-Out Button ---
signOutButton.translatesAutoresizingMaskIntoConstraints = false
signOutButton.setTitle("Sign Out", for: .normal)
view.addSubview(signOutButton)
NSLayoutConstraint.activate([
signOutButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
signOutButton.topAnchor.constraint(equalTo: signInButton.bottomAnchor, constant: 20),
])
signOutButton.addTarget(self, action: #selector(signOutButtonTapped), for: .touchUpInside)
// --- Set Initial UI State ---
updateUI(for: nil)
// Attempt to restore a previous sign-in session
GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in
if let user = user {
print("Successfully restored sign-in for user: \(user.profile?.givenName ?? "Unknown")")
// Print the ID token when a session is restored.
print("Restored ID Token: \(user.idToken?.tokenString ?? "")")
// On success, update the UI for the signed-in state on the main thread.
DispatchQueue.main.async {
self.updateUI(for: user)
}
}
}
}
// This method is called when the sign-in button is pressed.
@objc func signInButtonTapped() {
// Start the sign-in process.
GIDSignIn.sharedInstance.signIn(withPresenting: self) { signInResult, error in
guard let result = signInResult else {
// Inspect error
print("Error signing in: \(error?.localizedDescription ?? "No error description")")
return
}
// If sign in succeeded, print the ID token.
print("ID Token: \(result.user.idToken?.tokenString ?? "")")
DispatchQueue.main.async {
self.updateUI(for: result.user)
}
}
}
private func updateUI(for user: GIDGoogleUser?) {
if let user = user {
// User is signed in.
signInButton.isHidden = true
signOutButton.isHidden = false
welcomeLabel.isHidden = false
welcomeLabel.text = "Hello, \(user.profile?.givenName ?? "User")!"
} else {
// User is signed out.
signInButton.isHidden = false
signOutButton.isHidden = true
welcomeLabel.isHidden = true
}
}
@objc func signOutButtonTapped() {
GIDSignIn.sharedInstance.signOut()
// Update the UI for the signed-out state.
updateUI(for: nil)
}
}
اختبار ميزة "تسجيل الدخول بدون كلمة مرور"
بعد تسجيل الدخول، أغلِق التطبيق تمامًا وأعِد تشغيله. من المفترض أن يتم تسجيل دخولك تلقائيًا بدون الحاجة إلى النقر على الزر.
10. فهم الرمز المميز لتعريف الهوية
على الرغم من أنّ الكائن GIDGoogleUser مناسب لتخصيص واجهة المستخدم باستخدام اسم المستخدم وبريده الإلكتروني، فإنّ أهم جزء من البيانات التي يتم عرضها من حزمة تطوير البرامج (SDK) هو رمز التعريف.
يستخدم برنامج التدريب العملي هذا أداة على الإنترنت لفحص محتوى رمز JWT المميّز. في تطبيق متاح للجميع، يجب إرسال رمز التعريف المميز هذا إلى خادم الخلفية. يجب أن يتحقّق الخادم من سلامة الرمز المميّز للمعرّف واستخدام JWT لتنفيذ إجراء أكثر أهمية، مثل إنشاء حساب جديد على منصة الخلفية أو إنشاء جلسة جديدة للمستخدم.
الوصول إلى رمز JWT المميّز وفك ترميزه
- افتح تطبيقك.
- افتح وحدة تحكّم Xcode. من المفترض أن يظهر لك رمز مميّز مطبوع. سيبدو على النحو التالي:
eyJhbGciOiJSUzI1Ni ... Hecz6Wm4Q. - انسخ الرمز المميّز لتعريف الهوية واستخدِم أداة على الإنترنت، مثل jwt.io، لفك ترميز رمز JWT.
سيبدو رمز JWT الذي تم فك تشفيره على النحو التالي:
{
"alg": "RS256",
"kid": "c8ab71530972bba20b49f78a09c9852c43ff9118",
"typ": "JWT"
}
{
"iss": "https://accounts.google.com",
"azp": "171291171076-rrbkcjrp5jbte92ai9gub115ertscphi.apps.googleusercontent.com",
"aud": "171291171076-rrbkcjrp5jbte92ai9gub115ertscphi.apps.googleusercontent.com",
"sub": "10769150350006150715113082367",
"email": "example@example.com",
"email_verified": true,
"at_hash": "JyCYDmHtzhjkb0-qJhKsMg",
"name": "Kimya",
"picture": "https://lh3.googleusercontent.com/a/ACg8ocIyy4VoR31t_n0biPVcScBHwZOCRaKVDb_MoaMYep65fyqoAw=s96-c",
"given_name": "Kimya",
"iat": 1758645896,
"exp": 1758649496
}
حقول الرموز المميّزة البارزة
يحتوي رمز التعريف المميّز الذي تم فك ترميزه على حقول بأغراض مختلفة. بعضها سهل الفهم، مثل الاسم والبريد الإلكتروني، بينما يستخدم خادم الخلفية البعض الآخر للتحقّق من الهوية.
من المهم بشكل خاص فهم الحقل التالي:
- sub: الحقل
subهو معرّف فريد ودائم لحساب المستخدم على Google. يمكن للمستخدم تغيير عنوان البريد الإلكتروني الأساسي أو الاسم، ولكن لن يتغير معرّفsubأبدًا. وهذا يجعل الحقلsubالقيمة المثالية لاستخدامها كمفتاح أساسي لحسابات المستخدمين في الخلفية.
يتضمّن المقال الحصول على معلومات المستخدم من رمز التعريف المميز مزيدًا من المعلومات حول معنى جميع حقول الرمز المميز.
11. تأمين تطبيقك باستخدام خدمة App Check
ننصحك بشدة بتفعيل App Check لضمان أنّ تطبيقك فقط يمكنه الوصول إلى نقاط نهاية OAuth 2.0 من Google نيابةً عن مشروعك. تعمل خدمة App Check من خلال التحقّق من أنّ الطلبات المُرسَلة إلى خدمات الخلفية مصدرها تطبيقك الأصلي على جهاز حقيقي لم يتم التلاعب به.
يوضّح هذا القسم كيفية دمج خدمة App Check في تطبيقك وإعدادها لتصحيح الأخطاء في المحاكي ولإنشاء إصدار نهائي يعمل على جهاز حقيقي.
إعداد وحدة التحكّم
يتطلّب دمج App Check في تطبيقك إعدادًا لمرة واحدة في وحدتَي تحكّم Google Cloud وFirebase. يتضمّن ذلك تفعيل App Check لعميل OAuth على نظام التشغيل iOS في Google Cloud Console، وإنشاء مفتاح واجهة برمجة تطبيقات لاستخدامه مع موفّر تصحيح الأخطاء في App Check، وربط مشروعك على Google Cloud بخدمة Firebase.
تفعيل App Check في Google Cloud Console
- انتقِل إلى قائمة العملاء المرتبطين بمشروعك على Google Cloud.
- اختَر معرّف عميل OAuth 2.0 الذي أنشأته لتطبيق iOS.
- فعِّل App Check ضمن هوية Google على iOS

- انقر على حفظ.
إنشاء مفتاح واجهة برمجة تطبيقات
- انتقِل إلى صفحة مكتبة واجهات برمجة التطبيقات لمشروعك على Google Cloud.
- أدخِل Firebase App Check API في شريط البحث.

- اختَر Firebase App Check API وفعِّله.
- انتقِل إلى واجهات برمجة التطبيقات والخدمات وانقر على بيانات الاعتماد في قائمة التنقّل.
- انقر على إنشاء بيانات اعتماد في أعلى الصفحة.

- خصِّص اسمًا لمفتاح واجهة برمجة التطبيقات هذا.
- اختَر تطبيقات iOS ضِمن قيود التطبيقات.
- أضِف معرّف الحزمة لتطبيقك كتطبيق معتمَد.
- انقر على تقييد المفتاح ضمن قيود واجهة برمجة التطبيقات.
- اختَر Firebase App Check API من القائمة المنسدلة.
- انقر على إنشاء.

- انسخ مفتاح واجهة برمجة التطبيقات الذي تم إنشاؤه. ستحتاج إليه في خطوة لاحقة.
إضافة Firebase إلى مشروعك على Google Cloud
- انتقِل إلى وحدة تحكّم Firebase.
- انقر على البدء من خلال إعداد مشروع على Firebase.
- انقر على إضافة Firebase إلى مشروع Google Cloud.

- اختَر مشروعًا على Google Cloud من القائمة المنسدلة وواصِل عملية الاشتراك.
- انقر على إضافة Firebase.
- بعد أن يصبح مشروعك على Firebase جاهزًا، انقر على متابعة لفتح المشروع.
دمج الرمز البرمجي من جهة العميل
بعد إعداد مشروع Google Cloud لخدمة App Check، حان الوقت لكتابة الرمز البرمجي من جهة العميل لتفعيل الخدمة. يختلف مقدّم خدمة التصديق المستخدَم في بيئتَي الإنتاج وتصحيح الأخطاء. يستخدم تطبيق نهائي على جهاز حقيقي خدمة App Attest المضمّنة من Apple لإثبات صحته. ومع ذلك، بما أنّ محاكي iOS لا يمكنه تقديم هذا النوع من الشهادات، تتطلّب بيئة تصحيح الأخطاء موفّرًا خاصًا لتصحيح الأخطاء يتمّ تمرير مفتاح واجهة برمجة التطبيقات إليه.
يتعامل الرمز التالي مع كلتا الحالتين باستخدام توجيه للمترجم البرمجي لاختيار الموفّر الصحيح تلقائيًا في وقت الإنشاء.
SwiftUI
- افتح ملف التطبيق الرئيسي.
- حدِّد فئة
AppDelegateالتالية بعد عمليات الاستيراد وقبل السمة@main:
class AppDelegate: NSObject, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
#if targetEnvironment(simulator)
// Configure for debugging on a simulator.
// TODO: Replace "YOUR_API_KEY" with the key from your Google Cloud project.
let apiKey = "YOUR_API_KEY"
GIDSignIn.sharedInstance.configureDebugProvider(withAPIKey: apiKey) { error in
if let error {
print("Error configuring GIDSignIn debug provider: \(error)")
}
}
#else
// Configure GIDSignIn for App Check on a real device.
GIDSignIn.sharedInstance.configure { error in
if let error {
print("Error configuring GIDSignIn for App Check: \(error)")
} else {
print("GIDSignIn configured for App Check.")
}
}
#endif
return true
}
}
- استبدِل
"YOUR_API_KEY"في الرمز المقدَّم بمفتاح واجهة برمجة التطبيقات الذي نسخته من Google Cloud Console. - أضِف السطر التالي داخل بنية
App، قبل المتغيّرbodyمباشرةً. تسجّل هذه السمة فئة AppDelegate في دورة حياة التطبيق، ما يسمح لها بالاستجابة لعمليات تشغيل التطبيق وأحداث النظام الأخرى:
@UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
يجب أن يظهر ملف التطبيق الرئيسي على النحو التالي:
import GoogleSignIn
import SwiftUI
class AppDelegate: NSObject, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
#if targetEnvironment(simulator)
// Configure for debugging on a simulator.
// TODO: Replace "YOUR_API_KEY" with the key from your Google Cloud project.
let apiKey = "YOUR_API_KEY"
GIDSignIn.sharedInstance.configureDebugProvider(withAPIKey: apiKey) { error in
if let error {
print("Error configuring GIDSignIn debug provider: \(error)")
}
}
#else
// Configure GIDSignIn for App Check on a real device.
GIDSignIn.sharedInstance.configure { error in
if let error {
print("Error configuring GIDSignIn for App Check: \(error)")
} else {
print("GIDSignIn configured for App Check.")
}
}
#endif
return true
}
}
@main
struct iOS_Sign_in_with_Google_App: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL { url in
GIDSignIn.sharedInstance.handle(url)
}
}
}
}
UIKit
- افتح الملف AppDelegate.swift.
- عدِّل طريقة
application(_:didFinishLaunchingWithOptions:)لتتضمّن عملية إعداد App Check:
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
#if targetEnvironment(simulator)
// Configure for debugging on a simulator.
// TODO: Replace "YOUR_API_KEY" with the key from your Google Cloud project.
let apiKey = "YOUR_API_KEY"
GIDSignIn.sharedInstance.configureDebugProvider(withAPIKey: apiKey) { error in
if let error {
print("Error configuring GIDSignIn debug provider: \(error)")
}
}
#else
// Configure GIDSignIn for App Check on a real device.
GIDSignIn.sharedInstance.configure { error in
if let error {
print("Error configuring GIDSignIn for App Check: \(error)")
}
}
#endif
return true
}
- استبدِل
"YOUR_API_KEY"في الرمز المقدَّم بمفتاح واجهة برمجة التطبيقات الذي نسخته من Google Cloud Console.
يجب أن يبدو ملف AppDelegate.swift على النحو التالي:
import GoogleSignIn
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
#if targetEnvironment(simulator)
// Configure for debugging on a simulator.
// TODO: Replace "YOUR_API_KEY" with the key from your Google Cloud project.
let apiKey = "YOUR_API_KEY"
GIDSignIn.sharedInstance.configureDebugProvider(withAPIKey: apiKey) { error in
if let error {
print("Error configuring GIDSignIn debug provider: \(error)")
}
}
#else
// Configure GIDSignIn for App Check on a real device.
GIDSignIn.sharedInstance.configure { error in
if let error {
print("Error configuring GIDSignIn for App Check: \(error)")
}
}
#endif
return true
}
func application(
_ app: UIApplication,
open url: URL,
options: [UIApplication.OpenURLOptionsKey: Any] = [:]
) -> Bool {
var handled: Bool
handled = GIDSignIn.sharedInstance.handle(url)
if handled {
return true
}
// If not handled by this app, return false.
return false
}
// MARK: UISceneSession Lifecycle
func application(
_ application: UIApplication,
configurationForConnecting connectingSceneSession: UISceneSession,
options: UIScene.ConnectionOptions
) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(
name: "Default Configuration",
sessionRole: connectingSceneSession.role
)
}
func application(
_ application: UIApplication,
didDiscardSceneSessions sceneSessions: Set<UISceneSession>
) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
}
اختبار خدمة App Check على المحاكي
- في شريط قائمة Xcode، انتقِل إلى المنتج (Product) > المخطّط (Scheme) > تعديل المخطّط (Edit Scheme).
- انقر على تشغيل في قائمة التنقّل.
- انقر على علامة التبويب الوسيطات (Arguments).
- في قسم المَعلمات التي تم ضبطها عند الإطلاق (Arguments Passed on Launch)، انقر على + وأضِف -FIRDebugEnabled. تتيح وسيطة الإطلاق هذه تسجيل تصحيح الأخطاء في Firebase.
- اختَر إغلاق.

- شغِّل تطبيقك على المحاكي.
- انسخ الرمز المميز لتصحيح أخطاء App Check الذي تتم طباعته في وحدة تحكّم Xcode.

- انتقِل إلى مشروعك في وحدة تحكّم Firebase.
- وسِّع قسم إنشاء في قائمة التنقّل.
- اختَر App Check.
- انقر على علامة التبويب التطبيقات.
- مرِّر مؤشر الماوس فوق تطبيقك وانقر على رمز قائمة الخيارات الإضافية.

- انقر على إدارة رموز تصحيح الأخطاء.
- انقر على إضافة رمز تصحيح الأخطاء.
- أدخِل اسمًا لرمز التصحيح وألصِق رمز التصحيح الذي نسخته سابقًا في الحقل "القيمة".
- انقر على حفظ لتسجيل الرمز المميّز.

- ارجِع إلى المحاكي وسجِّل الدخول.
قد يستغرق ظهور المقاييس في وحدة التحكّم عدة دقائق. بعد ذلك، يمكنك التأكّد من أنّ خدمة App Check تعمل من خلال البحث عن زيادة في طلبات التحقّق في أحد المكانَين التاليَين:
- في قسم App Check ضِمن علامة التبويب "واجهات برمجة التطبيقات" في وحدة تحكّم Firebase

- في صفحة التعديل الخاصة بعميل OAuth في Google Cloud Console

بعد مراقبة مقاييس App Check في تطبيقك والتأكّد من التحقّق من الطلبات الصالحة، عليك تفعيل فرض استخدام App Check. وبعد فرضها، ترفض خدمة App Check جميع الطلبات التي لم يتم التحقّق منها، ما يضمن إمكانية وصول الزيارات من تطبيقك الأصلي فقط إلى نقاط نهاية OAuth 2.0 من Google نيابةً عن مشروعك.
12. مراجع إضافية
تهانينا!
لقد أعددت برنامج iOS لبروتوكول OAuth 2.0، وأضفت زر "تسجيل الدخول باستخدام Google" إلى تطبيق iOS، وتعرّفت على كيفية تخصيص مظهر الزر، وفكّ ترميز رمز تعريف JWT، وفعّلت خدمة App Check لتطبيقك.
قد تساعدك الروابط التالية في الخطوات التالية:
- كيفية بدء استخدام ميزة "تسجيل الدخول بحساب Google" على أجهزة iOS
- مستودع تسجيل الدخول بحساب Google لأجهزة iOS
- إثبات صحة رمز مميّز لمعرّف Google
- بدء استخدام App Check مع "تسجيل الدخول باستخدام حساب Google" على أجهزة iOS
- إبطال رموز الدخول وإلغاء ربط التطبيق
- مزيد من المعلومات حول مشاريع Google Cloud
- طُرق المصادقة في "هوية Google"
- تفعيل فرض استخدام App Check