הוספת כניסה באמצעות חשבון Google לאפליקציית iOS

1. לפני שמתחילים

בשיעור הזה תלמדו איך לפתח אפליקציית iOS שמטמיעה את התכונה 'כניסה באמצעות חשבון Google' ופועלת בסימולטור. אנחנו מספקים הטמעות שמשתמשות גם ב-SwiftUI וגם ב-UIKit.

‫SwiftUI הוא ה-framework המודרני של Apple לממשק משתמש, שמשמש לפיתוח אפליקציות חדשות. היא מאפשרת ליצור ממשקי משתמש לכל הפלטפורמות של אפל מבסיס קוד משותף יחיד. נדרשת גרסה מינימלית של iOS 13.

‫UIKit היא ה-framework המקורי והבסיסי של Apple לממשקי משתמש ב-iOS. הוא מספק תאימות לאחור לגרסאות ישנות יותר של iOS. לכן, זו בחירה טובה לאפליקציות ותיקות שצריכות לתמוך במגוון מכשירים ישנים.

אתם יכולים לבחור את המסגרת שהכי מתאימה לצרכים שלכם.

דרישות מוקדמות

מה תלמדו

  • איך יוצרים פרויקט ב-Google Cloud
  • איך יוצרים לקוחות OAuth ב-Google Cloud Console
  • איך מטמיעים את התכונה 'כניסה באמצעות חשבון Google' באפליקציית iOS
  • איך להתאים אישית את הכפתור לכניסה באמצעות חשבון Google
  • איך מפענחים אסימון מזהה
  • איך מפעילים את App Check באפליקציית iOS

הדרישות

ה-codelab הזה נוצר באמצעות Xcode 16.3 עם סימולטור iOS 18.3. מומלץ להשתמש בגרסה העדכנית של Xcode לפיתוח.

2. יצירת פרויקט חדש ב-Xcode

  1. פותחים את Xcode ובוחרים באפשרות Create a new Xcode project (יצירת פרויקט Xcode חדש).
  2. בוחרים בכרטיסייה iOS, בוחרים בתבנית אפליקציה ולוחצים על הבא.

דף התבנית ליצירת פרויקט Xcode

  1. באפשרויות הפרויקט:
    • מזינים את שם המוצר.
    • אפשר גם לבחור צוות.
    • מזינים את מזהה הארגון.
    • רושמים או זוכרים את מזהה החבילה שנוצר. תצטרכו אותו בהמשך.
    • בקטע ממשק, בוחרים באחת מהאפשרויות הבאות:
      • SwiftUI לאפליקציה שמבוססת על SwiftUI.
      • סטוריבורד לאפליקציה שמבוססת על UIKit.
    • בוחרים באפשרות Swift בשדה שפה.
    • לוחצים על הבא ובוחרים מיקום לשמירת הפרויקט.

דף האפשרויות של פרויקט Xcode

3. יצירת לקוח OAuth

כדי לאפשר לאפליקציה שלכם לתקשר עם שירותי האימות של Google, אתם צריכים ליצור מזהה לקוח OAuth. לשם כך נדרש פרויקט ב-Google Cloud. בהמשך מפורטים השלבים ליצירת פרויקט ומזהה לקוח OAuth.

בוחרים פרויקט קיים או יוצרים פרויקט חדש ב-Google Cloud.

  1. נכנסים אל Google Cloud Console ובוחרים פרויקט או יוצרים פרויקט. אם בוחרים פרויקט קיים, המסוף יפנה אתכם אוטומטית לשלב הבא שנדרש.

הדף לבחירת הפרויקט במסוף Google Cloud

  1. מזינים שם לפרויקט החדש ב-Google Cloud.
  2. בוחרים באפשרות יצירה.

הדף לבחירת הפרויקט במסוף Google Cloud

אם כבר הגדרתם מסך בקשת הסכמה לפרויקט שנבחר, לא תתבקשו להגדיר אותו עכשיו. במקרה כזה, אפשר לדלג על הקטע הזה ולעבור אל יצירת לקוח OAuth 2.0.

  1. בוחרים באפשרות הגדרת מסך בקשת ההסכמה.

דף יצירת לקוח OAuth ב-Google Cloud Console עם דרישה להגדרת מסך הסכמה

  1. בדף המיתוג, בוחרים באפשרות תחילת העבודה.

דף התחלת העבודה עם מיתוג במסוף Google Cloud

  1. בדף הגדרות הפרויקט ממלאים את השדות הבאים:
    • פרטי האפליקציה: מזינים שם וכתובת אימייל לתמיכה באפליקציה. כתובת האימייל הזו תוצג באופן ציבורי כדי שמשתמשים יוכלו לפנות אליכם עם שאלות לגבי ההסכמה שלהם.
    • קהל: בוחרים באפשרות חיצוני.
    • פרטים ליצירת קשר: מזינים כתובת אימייל שאליה Google יכולה לשלוח לכם הודעות לגבי הפרויקט.
    • קוראים את המדיניות של Google בנושא נתוני משתמשים בשירותי API.
    • לוחצים על יצירה.

דף ההגדרות של מיתוג הלקוח במסוף Google Cloud

  1. בתפריט הניווט, בוחרים בדף לקוחות.
  2. לוחצים על Create Client.

דף הלקוחות של פרויקט Google Cloud

יצירת לקוח OAuth 2.0

  1. ב-Application type בוחרים באפשרות iOS.
  2. מזינים שם ללקוח.
  3. מזינים את מזהה החבילה שנוצר בשלב הקודם.
  4. מזינים את מזהה הצוות שהוקצה לצוות על ידי Apple. השלב הזה הוא אופציונלי כרגע, אבל נדרש מזהה צוות כדי להפעיל את App Check בהמשך ה-codelab הזה.
  5. בוחרים באפשרות יצירה.

דף להזנת פרטים של לקוח OAuth

  1. מעתיקים את מזהה הלקוח מתיבת הדו-שיח. תצטרכו אותו בהמשך.
  2. מורידים את קובץ ה-plist כדי להשתמש בו בהמשך.

תיבת הדו-שיח 'נוצר מזהה לקוח OAuth'

4. הגדרת פרויקט Xcode

השלב הבא הוא להגדיר את פרויקט Xcode כך שיפעל עם Sign in with Google SDK. התהליך הזה כולל הוספה של ה-SDK לפרויקט כתלות והגדרה של הגדרות הפרויקט עם מזהה לקוח ייחודי. המזהה הזה מאפשר ל-SDK לתקשר באופן מאובטח עם שירות האימות של Google במהלך תהליך הכניסה.

התקנת יחסי התלות של 'כניסה באמצעות חשבון Google'

  1. פותחים את פרויקט Xcode.
  2. עוברים אל File > Add Package Dependencies (קובץ > הוספת תלות בחבילה).
  3. בסרגל החיפוש, מזינים את כתובת ה-URL של מאגר הכניסה באמצעות Google: https://github.com/google/GoogleSignIn-iOS

איתור התלות של 'כניסה באמצעות חשבון Google' ב-Swift Package Manager

  1. בוחרים באפשרות הוספת חבילה.
  2. בוחרים את יעד האפליקציה הראשי לחבילה GoogleSignIn.
  3. אם אתם משתמשים ב-SwiftUI, בוחרים את יעד האפליקציה הראשי לחבילה GoogleSignInSwift. אם אתם מתכננים להשתמש ב-UIKit, אל תבחרו יעד לחבילה הזו.
  4. בוחרים באפשרות הוספת חבילה.

הוספת תלות של 'כניסה באמצעות חשבון Google' לפרויקט

הגדרת פרטי הכניסה של האפליקציה

  1. בחלונית הניווט בפרויקט, לוחצים על שורש הפרויקט.
  2. באזור העריכה הראשי, בוחרים את יעד האפליקציה הראשי מהרשימה TARGETS.
  3. לוחצים על הכרטיסייה מידע בחלק העליון של אזור העריכה.
  4. מעבירים את העכבר מעל השורה האחרונה בקטע Custom iOS Target Properties (מאפייני טירגוט מותאמים אישית ל-iOS) ולוחצים על הלחצן + שמופיע.

הוספת מפתח טירגוט חדש למאפייני טירגוט ב-iOS

  1. בעמודה Key (מפתח), מקלידים GIDClientID.
  2. בעמודה Value (ערך), מדביקים את מזהה הלקוח שהעתקתם מ-Google Cloud Console.

הוספת GIDClientID ליעד האפליקציה הראשי

  1. פותחים את קובץ ה-plist שהורדתם ממסוף Google Cloud.
  2. מעתיקים את הערך של Reversed Client ID.

קובץ plist של מסוף Google Cloud

  1. מרחיבים את הקטע סוגי כתובות URL בתחתית הכרטיסייה מידע.
  2. לוחצים על הלחצן +.
  3. מזינים את מזהה הלקוח ההפוך בתיבה סכמות כתובות URL.

הוספת המפתח URLSchemes ליעד האפליקציה הראשי

עכשיו אפשר להתחיל להוסיף את לחצן הכניסה לאפליקציה.

5. הוספת לחצן הכניסה

אחרי שמגדירים את פרויקט Xcode, אפשר להתחיל להוסיף את הלחצן 'כניסה באמצעות חשבון Google' לאפליקציה.

הלוגיקה המרכזית של השלב הזה היא הקריאה ל-GIDSignIn.sharedInstance.signIn. השיטה הזו מתחילה את תהליך האימות ומעבירה את השליטה ל-SDK של 'כניסה באמצעות חשבון Google' כדי להציג למשתמש את תהליך הכניסה באמצעות חשבון Google.

SwiftUI

  1. מחפשים את הקובץ ContentView.swift בחלונית הניווט בפרויקט ב-Xcode.
  2. מחליפים את התוכן של הקובץ הזה בטקסט הבא:
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()
}

לחצן לכניסה באמצעות חשבון Google במסגרת SwiftUI בסימולטור iOS

UIKit

  1. מחפשים את הקובץ ViewController.swift בחלונית הניווט בפרויקט ב-Xcode.
  2. מחליפים את התוכן של הקובץ הזה בטקסט הבא:
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 בסימולטור iOS של UIKit framework

הצגת לחצן הכניסה

מפעילים את האפליקציה בסימולטור. יוצג לכם הלחצן 'כניסה באמצעות חשבון Google', אבל הוא עדיין לא יפעל כמו שצריך. זה צפוי, כי עדיין צריך להטמיע את הקוד כדי לטפל בהפניה חזרה לאפליקציה אחרי שהמשתמש מבצע אימות.

6. התאמה אישית של לחצן הכניסה

אתם יכולים להתאים אישית את לחצן ברירת המחדל של הכניסה באמצעות חשבון Google כדי שיתאים יותר לעיצוב האפליקציה שלכם. ערכת ה-SDK של 'כניסה באמצעות חשבון Google' מאפשרת לשנות את ערכת הצבעים והסגנון של הלחצן.

SwiftUI

לחצן ברירת המחדל מתווסף לדף באמצעות שורת הקוד הבאה:

GoogleSignInButton(action: handleSignInButton)

התג GoogleSignInButton מותאם אישית על ידי העברת פרמטרים לפונקציית האתחול שלו. הקוד הבא יגרום לכפתור הכניסה להופיע במצב כהה.

  1. פותחים את ContentView.swift.
  2. מעדכנים את הפונקציה לאתחול של GoogleSignInButton כך שתכיל את הערכים הבאים:
GoogleSignInButton(
  scheme: .dark,  // Options: .light, .dark, .auto
  style: .standard,  // Options: .standard, .wide, .icon
  state: .normal,  // Options: .normal, .disabled
  action: handleSignInButton
).padding()

כפתור כניסה באמצעות חשבון Google במצב כהה בסימולטור iOS של SwiftUI Framework

מידע נוסף על אפשרויות ההתאמה האישית זמין במאמר GoogleSignInSwift Framework Reference

UIKit

כברירת מחדל, הכפתור נוצר עם שורות הקוד הבאות:

// Create an instance of the Sign in with Google button
let signInButton = GIDSignInButton()

// Add the button to your view
view.addSubview(signInButton)

הלחצן GIDSignInButton מותאם אישית על ידי הגדרת מאפיינים במופע של הלחצן. הקוד הבא יגרום לכפתור הכניסה להופיע במצב כהה.

  1. פותחים את ViewController.swift.
  2. מוסיפים את שורות הקוד הבאות ממש לפני שמוסיפים את לחצן הכניסה לתצוגה בפונקציה viewDidLoad:
// Set the width and color of the sign-in button
signInButton.style = .standard  // Options: .standard, .wide, .iconOnly
signInButton.colorScheme = .dark  // Options: .dark, .light

כפתור לכניסה באמצעות חשבון Google במצב כהה בסימולטור iOS של UIKit framework

מידע נוסף על התאמה אישית זמין בחומר העזר בנושא GoogleSignIn Framework

7. טיפול בכתובת ה-URL להפניה אוטומטית לאימות

אחרי שמוסיפים את לחצן הכניסה, השלב הבא הוא לטפל בהפניה האוטומטית שמתרחשת אחרי שהמשתמש מבצע אימות. אחרי האימות, Google מחזירה כתובת URL עם קוד הרשאה זמני. כדי להשלים את תהליך הכניסה, רכיב handler מיירט את כתובת ה-URL הזו ומעביר אותה ל-SDK של הכניסה באמצעות חשבון Google כדי להחליף אותה באסימון מזהה חתום (JWT).

SwiftUI

  1. פותחים את הקובץ שמכיל את מבנה הנתונים App. שם הקובץ נקבע לפי שם הפרויקט, ולכן הוא ייראה בערך כך: YourProjectNameApp.swift.
  2. מחליפים את התוכן של הקובץ הזה בטקסט הבא:
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

  1. פותחים את AppDelegate.swift.
  2. מוסיפים את שורת הייבוא הבאה לחלק העליון של הקובץ:
import GoogleSignIn
  1. מוסיפים את פונקציית הטיפול באימות הבאה בתוך המחלקה 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

  1. פותחים את הקובץ ContentView.swift.
  2. מוסיפים משתנה מצב בחלק העליון של מבנה הנתונים ContentView. המשתנה הזה יכיל את פרטי המשתמש אחרי שהוא ייכנס לחשבון. מכיוון שזהו משתנה @State, ‏ SwiftUI יעדכן אוטומטית את ממשק המשתמש בכל פעם שהערך שלו ישתנה:
struct ContentView: View {
  @State private var user: GIDGoogleUser?
}
  1. מחליפים את 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()
    }
  }
}
  1. מעדכנים את בלוק ההשלמה 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 ?? "")")
  }
}
  1. מוסיפים פונקציה חדשה signOut לתחתית של מבנה הנתונים ContentView כדי שהיא תופעל על ידי לחצן היציאה:
func signOut() {
  GIDSignIn.sharedInstance.signOut()
  // After signing out, set the `user` state variable to `nil`.
  self.user = nil
}

מפעילים את האפליקציה ונכנסים לחשבון. אחרי אימות מוצלח, ממשק המשתמש אמור להשתנות.

מצב הכניסה למסגרת SwiftUI בסימולטור iOS

אחרי שמבצעים את השינויים האלה, הקובץ 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

  1. פותחים את ViewController.swift.
  2. בחלק העליון של ViewController, ממש מתחת למקום שבו הצהרתם על signInButton, מוסיפים לחצן יציאה ותווית ברוכים הבאים:
let signOutButton = UIButton(type: .system)
let welcomeLabel = UILabel()
  1. מוסיפים את הפונקציה הבאה לתחתית הקובץ 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
  }
}
  1. בתחתית הפונקציה 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)
  1. מעדכנים את הפונקציה 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)
    }
  }
}
  1. לבסוף, מוסיפים פונקציית signOutButtonTapped ל-ViewController כדי לטפל בתהליך היציאה מהחשבון:
@objc func signOutButtonTapped() {
  GIDSignIn.sharedInstance.signOut()
  // Update the UI for the signed-out state.
  updateUI(for: nil)
}

מפעילים את האפליקציה ונכנסים לחשבון. אחרי אימות מוצלח, ממשק המשתמש אמור להשתנות.

מצב הכניסה של Framework‏ UIKit בסימולטור iOS

אחרי שמבצעים את השינויים האלה, הקובץ 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. שחזור מצב הכניסה של משתמש

כדי לשפר את חוויית השימוש של משתמשים חוזרים, השלב הבא הוא לשחזר את מצב הכניסה שלהם כשהם מפעילים את האפליקציה. התקשרות אל restorePreviousSignIn משתמשת בפרטי הכניסה ששמורים ב-Keychain כדי להכניס את המשתמש שוב לחשבון באופן שקט, וכך המשתמש לא צריך להשלים את תהליך הכניסה בכל פעם.

SwiftUI

  1. פותחים את הקובץ ContentView.swift.
  2. מוסיפים את הקוד הבא מיד אחרי 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

  1. פותחים את ViewController.swift.
  2. מוסיפים את הקריאה 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 הוא אסימון ה-ID.

בשיעור הזה נשתמש בכלי אונליין כדי לבדוק את התוכן של ה-JWT. באפליקציה לייצור, צריך לשלוח את טוקן ה-ID הזה לשרת הקצה העורפי. השרת צריך לאמת את השלמות של טוקן הזהות ולהשתמש ב-JWT כדי לבצע פעולה משמעותית יותר, כמו יצירת חשבון חדש בפלטפורמת ה-Backend או יצירת סשן חדש למשתמש.

גישה לאסימון JWT ופענוח שלו

  1. מפעילים את האפליקציה.
  2. פותחים את מסוף Xcode. אסימון המזהה יודפס. היא תיראה בערך כך: eyJhbGciOiJSUzI1Ni ... Hecz6Wm4Q.
  3. מעתיקים את אסימון הזהות ומשתמשים בכלי אונליין כמו 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 פועלת על ידי אימות הבקשות לשירותי ה-Backend, כדי לוודא שהן מגיעות מהאפליקציה האותנטית שלכם במכשיר אמיתי שלא בוצעו בו שינויים.

בקטע הזה מוסבר איך לשלב את App Check באפליקציה ואיך להגדיר אותו לניפוי באגים בסימולטור ולגרסת ייצור שפועלת במכשיר אמיתי.

הגדרת המסוף

כדי לשלב את App Check באפליקציה, צריך לבצע הגדרה חד-פעמית במסוף Google Cloud ובמסוף Firebase. התהליך כולל הפעלה של App Check ללקוח OAuth של iOS ב-Google Cloud Console, יצירה של מפתח API לשימוש עם ספק הניפוי באגים של App Check וקישור של פרויקט Google Cloud ל-Firebase.

הפעלת App Check במסוף Google Cloud

  1. עוברים לרשימת הלקוחות שמשויכים לפרויקט ב-Google Cloud.
  2. בוחרים את מזהה הלקוח ב-OAuth 2.0 שיצרתם עבור אפליקציית iOS.
  3. מעבירים את המתג של App Check למצב מופעל בקטע Google Identity for iOS

דף העריכה של לקוח OAuth עם מתג App Check

  1. לוחצים על שמירה.

יצירה של מפתח API

  1. עוברים לדף API Library בפרויקט ב-Google Cloud.
  2. מזינים Firebase App Check API בסרגל החיפוש.

דף ספריית ה-API במסוף Google Cloud

  1. בוחרים את Firebase App Check API ומפעילים אותו.
  2. עוברים אל APIs & Services ובוחרים באפשרות Credentials בתפריט הניווט.
  3. לוחצים על יצירת פרטי כניסה בחלק העליון של הדף.

הדף API credentials (פרטי כניסה ל-API) במסוף Google Cloud

  1. נותנים שם למפתח ה-API.
  2. בקטע Application restrictions, בוחרים באפשרות iOS apps.
  3. מוסיפים את מזהה החבילה של האפליקציה כאפליקציה מאושרת.
  4. בקטע API restrictions, לוחצים על Restrict key.
  5. בתפריט הנפתח, בוחרים באפשרות Firebase App Check API.
  6. בוחרים באפשרות יצירה.

דף ליצירת מפתח Google Cloud API

  1. מעתיקים את מפתח ה-API שנוצר. תצטרכו אותו בשלב הבא.

הוספת Firebase לפרויקט ב-Google Cloud

  1. עוברים אל מסוף Firebase.
  2. בוחרים באפשרות Get started by setting up a Firebase project (מתחילים בהגדרת פרויקט ב-Firebase).
  3. בוחרים באפשרות הוספת Firebase לפרויקט Google Cloud.

הוספת Firebase לפרויקט קיים ב-Google Cloud

  1. בוחרים פרויקט ב-Google Cloud מהתפריט הנפתח וממשיכים בתהליך ההרשמה.
  2. בוחרים באפשרות הוספת Firebase.
  3. אחרי שהפרויקט ב-Firebase מוכן, לוחצים על המשך כדי לפתוח את הפרויקט.

שילוב קוד בצד הלקוח

אחרי שמגדירים את פרויקט Google Cloud לשימוש ב-App Check, צריך לכתוב את הקוד בצד הלקוח כדי להפעיל אותו. הספק שמשמש לאימות שונה בסביבות ייצור ובסביבות ניפוי באגים. אפליקציה שנמצאת בשלב ההפקה במכשיר אמיתי משתמשת בשירות App Attest המובנה של אפל כדי להוכיח את האותנטיות שלה. עם זאת, מכיוון שסימולטור iOS לא יכול לספק אישור כזה, סביבת הניפוי באגים דורשת ספק ניפוי באגים מיוחד שמועבר אליו מפתח API.

הקוד הבא מטפל בשני התרחישים באמצעות הנחיית קומפילציה לבחירה אוטומטית של הספק הנכון בזמן הבנייה.

SwiftUI

  1. פותחים את קובץ האפליקציה הראשי.
  2. מגדירים את המחלקה 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
  }
}
  1. מחליפים את הערך "YOUR_API_KEY" בקוד שמופיע למעלה במפתח ה-API שהעתקתם מ-Google Cloud Console.
  2. מוסיפים את השורה הבאה בתוך מבנה הנתונים 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

  1. פותחים את AppDelegate.swift.
  2. מעדכנים את השיטה 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
}
  1. מחליפים את הערך "YOUR_API_KEY" בקוד שמופיע למעלה במפתח ה-API שהעתקתם מ-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 באמולטור

  1. בסרגל התפריטים של Xcode, עוברים אל Product (מוצר) > Scheme (סכימה) > Edit Scheme (עריכת הסכימה).
  2. בתפריט הניווט, בוחרים באפשרות Run (הפעלה).
  3. בוחרים בכרטיסייה Arguments (ארגומנטים).
  4. בקטע Arguments Passed on Launch (ארגומנטים שהערך שלהם נקבע בהפעלה), לוחצים על + ומוסיפים את הערך ‎-FIRDebugEnabled. ארגומנט ההפעלה הזה מאפשר רישום ביומן של ניפוי באגים ב-Firebase.
  5. לוחצים על סגירה.

דף העריכה של הארגומנטים ב-Xcode

  1. מפעילים את האפליקציה בסימולטור.
  2. מעתיקים את אסימון ניפוי הבאגים של App Check שמוצג במסוף Xcode.

טוקן ניפוי באגים של App Check במסוף Xcode

  1. עוברים לפרויקט במסוף Firebase.
  2. מרחיבים את הקטע Build (פיתוח) בתפריט הניווט.
  3. בוחרים באפשרות בדיקת אפליקציות.
  4. בוחרים בכרטיסייה אפליקציות.
  5. מעבירים את העכבר מעל האפליקציה ולוחצים על סמל האפשרויות הנוספות (3 נקודות).

הגדרות של Firebase App Check

  1. בוחרים באפשרות ניהול אסימוני ניפוי באגים.
  2. לוחצים על הוספת טוקן לניפוי באגים.
  3. נותנים שם לטוקן לניפוי באגים ומדביקים את הטוקן לניפוי באגים שהעתקתם קודם לכן כערך.
  4. לוחצים על שמירה כדי לרשום את האסימון.

ניהול אסימוני ניפוי באגים ב-Firebase App Check

  1. חוזרים לסימולטור ונכנסים לחשבון.

יכול להיות שיעברו כמה דקות עד שהמדדים יופיעו במסוף. אחרי שהם יבצעו את הפעולה, תוכלו לוודא ש-App Check פועל על ידי חיפוש עלייה במספר הבקשות המאומתות באחד משני המקומות הבאים:

  • בקטע App Check במסוף Firebase, בכרטיסייה APIs.

מדדים של Firebase App Check

  • בדף העריכה של לקוח OAuth ב-Google Cloud Console.

מדדים של בדיקת אפליקציות במסוף Google Cloud

אחרי שתעקבו אחרי מדדי App Check של האפליקציה ותוודאו שהבקשות הלגיטימיות מאומתות, כדאי להפעיל את האכיפה של App Check. אחרי שהאכיפה תופעל, App Check ידחה את כל הבקשות שלא אומתו, וכך יבטיח שרק תנועה מהאפליקציה האותנטית שלכם תוכל לגשת לנקודות הקצה של Google OAuth 2.0 בשם הפרויקט שלכם.

12. מקורות מידע נוספים

מעולה!

הגדרתם לקוח iOS OAuth 2.0, הוספתם לחצן 'כניסה באמצעות Google' לאפליקציית iOS, למדתם איך להתאים אישית את המראה של הלחצן, פענחתם אסימון מזהה JWT והפעלתם את App Check באפליקציה.

הקישורים הבאים יכולים לעזור לכם בשלבים הבאים:

שאלות נפוצות