1. Prima di iniziare
Questo codelab ti guida nella creazione di un'applicazione per iOS che implementa Accedi con Google e viene eseguita in un simulatore. Vengono fornite implementazioni che utilizzano sia SwiftUI sia UIKit.
SwiftUI è il framework UI moderno di Apple per lo sviluppo di nuove app. Consente di creare interfacce utente per tutte le piattaforme Apple da un unico codebase condiviso. Richiede una versione minima di iOS 13.
UIKit è il framework UI originale e fondamentale di Apple per iOS. Fornisce la compatibilità con le versioni precedenti di iOS. Ciò lo rende una buona scelta per le app consolidate che devono supportare una serie di dispositivi meno recenti.
Puoi seguire il percorso del framework più in linea con le tue esigenze di sviluppo.
Prerequisiti
Obiettivi didattici
- Come creare un progetto Google Cloud
- Come creare client OAuth nella console Google Cloud
- Come implementare Accedi con Google per la tua app per iOS
- Come personalizzare il pulsante Accedi con Google
- Come decodificare un token ID
- Come attivare App Check per la tua app per iOS
Che cosa ti serve
- Una versione attuale di Xcode
- Un computer con macOS che soddisfi i requisiti di sistema per la versione di Xcode installata
Questo codelab è stato creato utilizzando Xcode 16.3 con il simulatore iOS 18.3. Per lo sviluppo, devi utilizzare l'ultima versione di Xcode.
2. Crea un nuovo progetto Xcode
- Apri Xcode e seleziona Crea un nuovo progetto Xcode.
- Scegli la scheda iOS, seleziona il modello App e fai clic su Avanti.

- Nelle opzioni del progetto:
- Inserisci il nome del prodotto.
- (Facoltativo) Seleziona il team.
- Inserisci l'identificatore organizzazione.
- Prendi nota dell'identificatore pacchetto generato. Ti servirà in un secondo momento.
- Per Interfaccia, scegli una delle seguenti opzioni:
- SwiftUI per un'app basata su SwiftUI.
- Storyboard per un'app basata su UIKit.
- Scegli Swift per Lingua.
- Fai clic su Avanti e scegli una posizione in cui salvare il progetto.

3. Crea un client OAuth
Per consentire alla tua app di comunicare con i servizi di autenticazione di Google, devi creare un ID client OAuth. Per farlo, è necessario un progetto Google Cloud. I seguenti passaggi ti guideranno nella creazione di un progetto e di un ID client OAuth.
Seleziona o crea un progetto Google Cloud
- Vai alla console Google Cloud e seleziona o crea un progetto. Se selezioni un progetto preesistente, la console ti indirizzerà automaticamente al passaggio successivo richiesto.

- Inserisci un nome per il nuovo progetto Google Cloud.
- Seleziona Crea.

Configurare la schermata di consenso
Se hai già configurato una schermata per il consenso per il progetto selezionato, non ti verrà chiesto di configurarla ora. In questo caso, puoi saltare questa sezione e passare a Creare un client OAuth 2.0.
- Seleziona Configura schermata di consenso.

- Seleziona Inizia nella pagina del branding.

- Nella pagina di configurazione del progetto, compila i seguenti campi:
- Informazioni sull'app: inserisci un nome e un'email dell'assistenza utente per la tua app. Questa email dell'assistenza verrà visualizzata pubblicamente per consentire agli utenti di contattarti in caso di domande sul consenso.
- Pubblico: seleziona Esterno.
- Dati di contatto: inserisci un indirizzo email affinché Google possa contattarti in merito al tuo progetto.
- Leggi le Norme relative ai dati utente dei servizi API di Google.
- Fai clic su Crea.

- Seleziona la pagina Clienti nel menu di navigazione.
- Fai clic su Crea client.

Crea un client OAuth 2.0
- Seleziona iOS per Tipo di applicazione.
- Inserisci un nome per il cliente.
- Inserisci l'identificatore bundle creato nell'ultimo passaggio.
- Inserisci l'ID team assegnato al tuo team da Apple. Questo passaggio è facoltativo per ora, ma è necessario un ID team per abilitare App Check più avanti in questo codelab.
- Seleziona Crea.

- Copia l'ID client dalla finestra di dialogo. Ti servirà in un secondo momento.
- Scarica il file plist per consultarlo in un secondo momento.

4. Configurare il progetto Xcode
Il passaggio successivo consiste nel configurare il progetto Xcode per l'utilizzo dell'SDK Sign in with Google. Questo processo prevede l'aggiunta dell'SDK al progetto come dipendenza e la configurazione delle impostazioni del progetto con un ID client univoco. Questo ID consente all'SDK di comunicare in modo sicuro con il servizio di autenticazione di Google durante la procedura di accesso.
Installare le dipendenze di Accedi con Google
- Apri il progetto Xcode.
- Vai a File > Add Package Dependencies (File > Aggiungi dipendenze pacchetto).
- Nella barra di ricerca, inserisci l'URL del repository Accedi con Google: https://github.com/google/GoogleSignIn-iOS

- Seleziona Aggiungi pacchetto.
- Seleziona l'applicazione di destinazione principale per il pacchetto GoogleSignIn.
- Se utilizzi SwiftUI, seleziona il target dell'applicazione principale per il pacchetto GoogleSignInSwift. Se prevedi di utilizzare UIKit, non selezionare una destinazione per questo pacchetto.
- Seleziona Aggiungi pacchetto.

Configurare le credenziali dell'app
- Nel navigatore del progetto, fai clic sulla radice del progetto.
- Nell'area principale dell'editor, seleziona il target dell'applicazione principale dall'elenco TARGET.
- Seleziona la scheda Informazioni nella parte superiore dell'area dell'editor.
- Passa il mouse sopra l'ultima riga della sezione Proprietà di targeting iOS personalizzate e fai clic sul pulsante + visualizzato.

- Nella colonna Key, digita GIDClientID.
- Nella colonna Valore, incolla l'ID client copiato dalla console Google Cloud.

- Apri il file plist che hai scaricato da Google Cloud Console.
- Copia il valore di ID client invertito.

- Espandi Tipi di URL nella parte inferiore della scheda Informazioni.
- Seleziona il pulsante +.
- Inserisci l'ID client invertito nella casella Schemi URL.

Ora possiamo iniziare ad aggiungere il pulsante di accesso alla nostra app.
5. Aggiungere il pulsante di accesso
Ora che il progetto Xcode è configurato, è il momento di iniziare ad aggiungere il pulsante Accedi con Google all'app.
La logica principale di questo passaggio è la chiamata a GIDSignIn.sharedInstance.signIn. Questo metodo avvia la procedura di autenticazione, trasferendo il controllo all'SDK di Accedi con Google per presentare il flusso di accesso con Google all'utente.
SwiftUI
- Individua il file ContentView.swift nel navigatore del progetto Xcode.
- Sostituisci i contenuti di questo file con il seguente testo:
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
- Individua il file ViewController.swift nel navigatore del progetto Xcode.
- Sostituisci i contenuti di questo file con il seguente testo:
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 ?? "")")
}
}
}

Visualizzare il pulsante di accesso
Avvia l'app nel simulatore. Vedrai il pulsante Accedi con Google, ma non funzionerà ancora correttamente. Questo è previsto, in quanto devi ancora implementare il codice per gestire il reindirizzamento all'app dopo l'autenticazione dell'utente.
6. Personalizzare il pulsante di accesso
Puoi personalizzare il pulsante predefinito Accedi con Google per adattarlo meglio al tema della tua app. L'SDK Accedi con Google ti consente di modificare lo schema di colori e lo stile del pulsante.
SwiftUI
Il pulsante predefinito viene aggiunto alla pagina con questa riga di codice:
GoogleSignInButton(action: handleSignInButton)
GoogleSignInButton viene personalizzato passando i parametri al relativo inizializzatore. Il seguente codice farà in modo che il pulsante di accesso venga visualizzato in modalità Buio.
- Apri ContentView.swift
- Aggiorna l'inizializzatore per
GoogleSignInButtonin modo che contenga i seguenti valori:
GoogleSignInButton(
scheme: .dark, // Options: .light, .dark, .auto
style: .standard, // Options: .standard, .wide, .icon
state: .normal, // Options: .normal, .disabled
action: handleSignInButton
).padding()

Per ulteriori informazioni sulle opzioni di personalizzazione, consulta il riferimento al framework GoogleSignInSwift.
UIKit
Il pulsante predefinito viene creato con queste righe di codice:
// Create an instance of the Sign in with Google button
let signInButton = GIDSignInButton()
// Add the button to your view
view.addSubview(signInButton)
Il GIDSignInButton viene personalizzato impostando le proprietà dell'istanza del pulsante. Il seguente codice farà in modo che il pulsante di accesso venga visualizzato in modalità Buio.
- Apri ViewController.swift.
- Aggiungi le seguenti righe di codice immediatamente prima di aggiungere il pulsante di accesso alla visualizzazione nella funzione
viewDidLoad:
// Set the width and color of the sign-in button
signInButton.style = .standard // Options: .standard, .wide, .iconOnly
signInButton.colorScheme = .dark // Options: .dark, .light

Per ulteriori informazioni sulla personalizzazione, consulta il riferimento al framework GoogleSignIn.
7. Gestire l'URL di reindirizzamento dell'autenticazione
Dopo aver aggiunto il pulsante di accesso, il passaggio successivo consiste nel gestire il reindirizzamento che si verifica dopo l'autenticazione di un utente. Dopo l'autenticazione, Google restituisce un URL con un codice di autorizzazione temporaneo. Per completare la procedura di accesso, un gestore intercetta questo URL e lo passa all'SDK Sign in with Google per essere scambiato con un token ID firmato (JWT).
SwiftUI
- Apri il file che contiene la struttura
App. Il nome di questo file si basa sul tuo progetto, quindi sarà simile a YourProjectNameApp.swift. - Sostituisci i contenuti di questo file con il seguente testo:
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
- Apri AppDelegate.swift.
- Aggiungi la seguente importazione all'inizio del file:
import GoogleSignIn
- Aggiungi la seguente funzione di gestione dell'autenticazione all'interno della classe
AppDelegate. Un buon punto in cui posizionarlo è subito dopo la parentesi graffa chiusa del metodoapplication(_: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
}
Dopo aver apportato queste modifiche, il file AppDelegate.swift dovrebbe essere simile al seguente:
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.
}
}
Testare il flusso di accesso
Ora puoi testare il flusso di accesso completo.
Esegui l'app e tocca il pulsante di accesso. Dopo l'autenticazione, Google mostrerà una schermata di consenso in cui potrai concedere all'app l'autorizzazione ad accedere alle tue informazioni. Una volta approvato, l'accesso verrà completato e tornerai all'app.
Al termine della procedura di accesso, l'SDK Sign in with Google archivia in modo sicuro le credenziali dell'utente nel portachiavi del dispositivo. Queste credenziali possono essere utilizzate in un secondo momento per consentire a un utente di rimanere connesso nei successivi avvii dell'app.
8. Aggiungere un pulsante di disconnessione
Ora che l'accesso funziona, il passaggio successivo consiste nell'aggiungere un pulsante di disconnessione e aggiornare la UI in modo che rifletta lo stato di accesso attuale dell'utente. Quando l'accesso va a buon fine, l'SDK fornisce un oggetto GIDGoogleUser. Questo oggetto contiene una proprietà profile con informazioni di base come il nome e l'email dell'utente, che utilizzerai per personalizzare la UI.
SwiftUI
- Apri il file ContentView.swift.
- Aggiungi una variabile di stato nella parte superiore della struttura
ContentView. Questa variabile conterrà le informazioni dell'utente dopo l'accesso. Poiché si tratta di una variabile@State, SwiftUI aggiornerà automaticamente la tua UI ogni volta che il suo valore cambia:
struct ContentView: View {
@State private var user: GIDGoogleUser?
}
- Sostituisci l'attuale
bodydella strutturaContentViewcon il seguenteVStack. Verrà verificato se la variabile di statousercontiene un utente. In questo caso, verrà visualizzato un messaggio di benvenuto e un pulsante di disconnessione. In caso contrario, verrà visualizzato il pulsante Accedi con Google originale:
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()
}
}
}
- Aggiorna il blocco di completamento
handleSignInButtonper assegnaresignInResult.useralla nuova variabileuser. Ecco cosa attiva il passaggio della UI alla visualizzazione con accesso:
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 ?? "")")
}
}
- Aggiungi una nuova funzione
signOutalla fine della structContentViewda chiamare dal pulsante di disconnessione:
func signOut() {
GIDSignIn.sharedInstance.signOut()
// After signing out, set the `user` state variable to `nil`.
self.user = nil
}
Avvia l'app e accedi. Dovresti vedere l'interfaccia utente cambiare dopo un'autenticazione riuscita.

Dopo aver apportato queste modifiche, il file ContentView.swift dovrebbe avere il seguente aspetto:
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
- Apri ViewController.swift.
- Nella parte superiore di
ViewController, direttamente sotto la dichiarazione disignInButton, aggiungi un pulsante di disconnessione e un'etichetta di benvenuto:
let signOutButton = UIButton(type: .system)
let welcomeLabel = UILabel()
- Aggiungi la seguente funzione alla fine di
ViewController. Questa funzione mostrerà un'interfaccia utente diversa in base allo stato di accesso dell'utente:
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
}
}
- Nella parte inferiore della funzione
viewDidLoad, aggiungi il seguente codice per aggiungere l'etichetta di benvenuto e il pulsante di disconnessione alla visualizzazione:
// --- 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)
- Aggiorna la funzione
signInButtonTappedper chiamare il metodoUpdateUIin caso di accesso riuscito:
@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)
}
}
}
- Infine, aggiungi una funzione
signOutButtonTappedaViewControllerper gestire la procedura di disconnessione:
@objc func signOutButtonTapped() {
GIDSignIn.sharedInstance.signOut()
// Update the UI for the signed-out state.
updateUI(for: nil)
}
Avvia l'app e accedi. Dovresti vedere l'interfaccia utente cambiare dopo un'autenticazione riuscita.

Dopo aver apportato queste modifiche, il file ViewController.swift dovrebbe essere simile al seguente:
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. Ripristinare lo stato di accesso di un utente
Per migliorare l'esperienza degli utenti di ritorno, il passaggio successivo consiste nel ripristinare il loro stato di accesso all'avvio dell'app. La chiamata restorePreviousSignIn utilizza le credenziali salvate nel portachiavi per consentire all'utente di accedere di nuovo in modo silenzioso, in modo che non debba completare il flusso di accesso ogni volta.
SwiftUI
- Apri ContentView.swift.
- Aggiungi il seguente codice subito dopo
VStackall'interno della variabilebody:
.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 ?? "")")
}
}
}
Il file ContentView.swift dovrebbe essere simile al seguente:
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
- Apri ViewController.swift.
- Aggiungi la seguente chiamata
restorePreviousSignInalla fine del metodoviewDidLoad:
// 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)
}
}
}
Il file ViewController.swift dovrebbe avere il seguente aspetto:
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)
}
}
Testare l'accesso silenzioso
Dopo aver eseguito l'accesso, chiudi completamente l'app e riavviala. Dovresti vedere che ora l'accesso viene eseguito automaticamente senza dover toccare il pulsante.
10. Informazioni sul token ID
Sebbene l'oggetto GIDGoogleUser sia utile per personalizzare la UI utilizzando il nome e l'email dell'utente, il dato più importante restituito dall'SDK è il token ID.
Questo codelab utilizza uno strumento online per esaminare i contenuti del JWT. In un'app di produzione, devi inviare questo token ID al server di backend. Il server deve verificare l'integrità del token ID e utilizzare il JWT per fare qualcosa di più significativo, ad esempio creare un nuovo account sulla piattaforma di backend o stabilire una nuova sessione per l'utente.
Accedere al token JWT e decodificarlo
- Avvia l'app.
- Apri la console Xcode. Dovresti vedere un token ID stampato. Avrà un aspetto simile a questo:
eyJhbGciOiJSUzI1Ni ... Hecz6Wm4Q. - Copia il token ID e utilizza uno strumento online come jwt.io per decodificare il JWT.
Il JWT decodificato avrà il seguente aspetto:
{
"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
}
Campi token importanti
Il token ID decodificato contiene campi con scopi diversi. Alcuni sono facili da capire, come nome ed email, mentre altri vengono utilizzati dal server di backend per la verifica.
Il seguente campo è particolarmente importante da comprendere:
- sub: il campo
subè un identificatore univoco e permanente dell'Account Google dell'utente. Un utente può modificare il proprio indirizzo email principale o il proprio nome, ma il suo IDsubnon cambierà mai. In questo modo, il camposubdiventa il valore perfetto da utilizzare come chiave primaria per gli account utente di backend.
Ottenere informazioni utente dal token ID fornisce ulteriori informazioni sul significato di tutti i campi del token.
11. Proteggere l'app con App Check
Ti consigliamo vivamente di attivare App Check per assicurarti che solo la tua app possa accedere agli endpoint OAuth 2.0 di Google per conto del tuo progetto. App Check funziona verificando che le richieste ai tuoi servizi di backend provengano dalla tua app autentica su un dispositivo reale e non manomesso.
Questa sezione mostra come integrare App Check nella tua app e configurarlo sia per il debug in un simulatore sia per una build di produzione in esecuzione su un dispositivo reale.
Configurazione della console
L'integrazione di App Check nella tua applicazione richiede una configurazione una tantum nelle console Google Cloud e Firebase. Ciò comporta l'attivazione di App Check per il client OAuth iOS nella console Google Cloud, la creazione di una chiave API da utilizzare con il fornitore di debug App Check e il collegamento del progetto Google Cloud a Firebase.
Attivare App Check nella console Google Cloud
- Vai all'elenco dei client associati al tuo progetto Google Cloud.
- Seleziona l'ID client OAuth 2.0 che hai creato per la tua app per iOS.
- Attiva App Check in Google Identity per iOS.

- Fai clic su Salva.
Crea una chiave API
- Vai alla pagina Libreria API per il tuo progetto Google Cloud.
- Inserisci API Firebase App Check nella barra di ricerca.

- Seleziona e attiva l'API Firebase App Check.
- Vai ad API e servizi e seleziona Credenziali nel menu di navigazione.
- Seleziona Crea credenziali nella parte superiore della pagina.

- Assegna un nome a questa chiave API.
- Seleziona le app per iOS in Restrizioni delle applicazioni.
- Aggiungi l'identificatore del bundle della tua app come applicazione approvata.
- Seleziona Limita chiave in Restrizioni delle API.
- Seleziona API Firebase App Check dal menu a discesa.
- Seleziona Crea.

- Copia la chiave API creata. Ti servirà in un passaggio successivo.
Aggiungere Firebase al tuo progetto Google Cloud
- Vai alla console Firebase.
- Seleziona Per iniziare, configura un progetto Firebase.
- Seleziona Aggiungi Firebase al progetto Google Cloud.

- Seleziona un progetto Google Cloud dal menu a discesa e continua la procedura di registrazione.
- Seleziona Aggiungi Firebase.
- Una volta pronto il progetto Firebase, seleziona Continua per aprirlo.
Integrazione del codice lato client
Con il progetto Google Cloud configurato per App Check, è il momento di scrivere il codice lato client per attivarlo. Il fornitore utilizzato per l'attestazione è diverso negli ambienti di produzione e di debug. Un'app di produzione su un dispositivo reale utilizza il servizio App Attest integrato di Apple per dimostrare la sua autenticità. Tuttavia, poiché il simulatore iOS non può fornire questo tipo di attestazione, l'ambiente di debug richiede un provider di debug speciale a cui viene passata una chiave API.
Il seguente codice gestisce entrambi gli scenari utilizzando una direttiva del compilatore per selezionare automaticamente il provider corretto al momento della build.
SwiftUI
- Apri il file dell'app principale.
- Definisci la seguente classe
AppDelegatedopo le importazioni e prima dell'attributo@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
}
}
- Sostituisci
"YOUR_API_KEY"nel codice fornito con la chiave API che hai copiato da Google Cloud Console. - Aggiungi la seguente riga all'interno della struttura
App, subito prima della variabilebody. In questo modo, la classe AppDelegate viene registrata con il ciclo di vita dell'app, consentendole di rispondere all'avvio dell'app e ad altri eventi di sistema:
@UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
Il file dell'app principale dovrebbe avere il seguente aspetto:
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
- Apri AppDelegate.swift.
- Aggiorna il metodo
application(_:didFinishLaunchingWithOptions:)in modo che contenga l'inizializzazione di 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
}
- Sostituisci
"YOUR_API_KEY"nel codice fornito con la chiave API che hai copiato da Google Cloud Console.
Il file AppDelegate.swift dovrebbe avere il seguente aspetto:
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.
}
}
Testare App Check sul simulatore
- Nella barra dei menu di Xcode, vai a Product (Prodotto) > Scheme (Schema) > Edit Scheme (Modifica schema).
- Nel menu di navigazione, seleziona Esegui.
- Seleziona la scheda Arguments (Argomenti).
- Nella sezione Arguments Passed on Launch (Argomenti passati al momento dell'avvio), seleziona + e aggiungi -FIRDebugEnabled. Questo argomento di avvio abilita la registrazione di debug di Firebase.
- Seleziona Chiudi.

- Avvia l'app sul simulatore.
- Copia il token di debug di App Check stampato nella console Xcode.

- Vai al tuo progetto nella console Firebase.
- Espandi la sezione Crea nel menu di navigazione.
- Seleziona Controllo app.
- Seleziona la scheda App.
- Passa il mouse sopra l'app e seleziona l'icona del menu con tre puntini.

- Seleziona Gestisci i token di debug.
- Seleziona Aggiungi token di debug.
- Assegna un nome al token di debug e incolla il token di debug che hai copiato in precedenza per il valore.
- Seleziona Salva per registrare il token.

- Torna al simulatore e accedi.
Potrebbero essere necessari diversi minuti prima che le metriche vengano visualizzate nella console. Una volta fatto, puoi verificare che App Check funzioni cercando un aumento delle richieste verificate in uno dei due punti seguenti:
- Nella sezione App Check della console Firebase, nella scheda API.

- Nella pagina di modifica del client OAuth nella console Google Cloud.

Dopo aver monitorato le metriche di App Check della tua app e aver confermato che le richieste legittime vengono verificate, devi attivare l'applicazione di App Check. Una volta applicato, App Check rifiuta tutte le richieste non verificate, garantendo che solo il traffico proveniente dalla tua app autentica possa accedere agli endpoint OAuth 2.0 di Google per conto del tuo progetto.
12. Risorse aggiuntive
Complimenti!
Hai configurato un client iOS OAuth 2.0, aggiunto un pulsante Accedi con Google a un'app per iOS, imparato a personalizzare l'aspetto del pulsante, decodificato un token ID JWT e attivato App Check per la tua app.
Questi link possono aiutarti con i passaggi successivi:
- Come iniziare a utilizzare Accedi con Google per iOS
- Repository Accedi con Google per iOS
- Verificare un token ID Google
- Iniziare a utilizzare App Check per Accedi con Google su iOS
- Revoca dei token di accesso e disconnessione dell'app
- Scopri di più sui progetti Google Cloud
- Metodi di autenticazione di Google Identity
- Attivare l'applicazione forzata di App Check