1. Antes de começar
Este codelab mostra como criar um aplicativo iOS que implementa o recurso Fazer login com o Google e é executado em um simulador. Implementações usando SwiftUI e UIKit são fornecidas.
O SwiftUI é o framework de interface moderno da Apple para o desenvolvimento de novos apps. Ele permite criar interfaces de usuário para todas as plataformas da Apple com uma única base de código compartilhada. É necessário ter no mínimo a versão 13 do iOS.
O UIKit é o framework de UI original e fundamental da Apple para iOS. Ela oferece compatibilidade com versões anteriores do iOS. Isso a torna uma boa opção para apps estabelecidos que precisam oferecer suporte a vários dispositivos mais antigos.
Siga o caminho do framework que melhor se alinha às suas necessidades de desenvolvimento.
Pré-requisitos
O que você vai aprender
- Como criar um projeto do Google Cloud
- Como criar clientes OAuth no Console do Google Cloud
- Como implementar o recurso Fazer login com o Google no seu app iOS
- Como personalizar o botão "Fazer login com o Google"
- Como decodificar um token de ID
- Como ativar o App Check no seu app iOS
O que é necessário
- Uma versão atual do Xcode
- Um computador com macOS que atenda aos requisitos do sistema da versão do Xcode instalada
Este codelab foi criado usando o Xcode 16.3 com o simulador do iOS 18.3. Use a versão mais recente do Xcode para desenvolvimento.
2. Criar um projeto do Xcode
- Abra o Xcode e selecione Criar um projeto do Xcode.
- Escolha a guia iOS, selecione o modelo App e clique em Next.

- Nas opções do projeto:
- Insira o Nome do produto.
- Se quiser, selecione sua Equipe.
- Insira o identificador da organização.
- Anote o identificador do pacote gerado. Você precisará dessas informações posteriormente.
- Em Interface, escolha uma das opções:
- SwiftUI para um app baseado em SwiftUI.
- Storyboard para um app baseado em UIKit.
- Escolha Swift para o Idioma.
- Clique em Próxima e escolha um local para salvar o projeto.

3. Criar um cliente OAuth
Para permitir que seu app se comunique com os serviços de autenticação do Google, crie um ID do cliente OAuth. Isso requer um projeto do Google Cloud. As etapas a seguir orientam você no processo de criação de um projeto e um ID do cliente OAuth.
Selecionar ou criar um projeto do Google Cloud
- Acesse o Console do Google Cloud e selecione ou crie um projeto. Se você selecionar um projeto preexistente, o console vai direcionar você automaticamente para a próxima etapa necessária.

- Insira um nome para seu novo projeto do Google Cloud.
- Selecione Criar.

Configurar a tela de consentimento
Se você já tiver configurado uma tela de consentimento para o projeto selecionado, não será necessário fazer isso agora. Nesse caso, pule esta seção e vá para Criar um cliente OAuth 2.0.
- Selecione Configurar tela de consentimento.

- Selecione Começar na página de branding.

- Na página de configuração do projeto, preencha os seguintes campos:
- Informações do app: insira um nome e um e-mail de suporte ao usuário para seu app. Esse e-mail de suporte será exibido publicamente para que os usuários entrem em contato com você se tiverem dúvidas sobre o consentimento deles.
- Público-alvo: selecione Externo.
- Dados de contato: digite um endereço de e-mail para que o Google entre em contato com você sobre seu projeto.
- Leia a Política de dados do usuário dos serviços de API do Google.
- Clique em Criar.

- Selecione a página Clientes no menu de navegação.
- Clique em Criar cliente.

Criar um cliente OAuth 2.0
- Selecione iOS em Tipo de aplicativo.
- Insira um nome para o cliente.
- Insira o Identificador do pacote criado na última etapa.
- Insira o ID da equipe atribuído a ela pela Apple. Por enquanto, essa etapa é opcional, mas um ID da equipe é necessário para ativar o App Check mais tarde neste codelab.
- Selecione Criar.

- Copie o ID do cliente da janela de diálogo. Você vai precisar dele mais tarde.
- Faça o download do arquivo plist para consultar depois.

4. Configurar o projeto do Xcode
A próxima etapa é configurar seu projeto Xcode para trabalhar com o SDK Sign-in com o Google. Esse processo envolve adicionar o SDK ao seu projeto como uma dependência e configurar as definições do projeto com um ID do cliente exclusivo. Esse ID permite que o SDK se comunique com segurança com o serviço de autenticação do Google durante o processo de login.
Instalar as dependências do recurso "Fazer login com o Google"
- Abra seu projeto do Xcode.
- Navegue até Arquivo > Adicionar dependências de pacote.
- Na barra de pesquisa, insira o URL do repositório "Fazer login com o Google": https://github.com/google/GoogleSignIn-iOS

- Selecione Adicionar pacote.
- Selecione o destino principal do aplicativo para o pacote GoogleSignIn.
- Se você estiver usando a SwiftUI, selecione o destino principal do aplicativo para o pacote GoogleSignInSwift. Se você planeja usar o UIKit, não selecione um destino para este pacote.
- Selecione Adicionar pacote.

Configurar as credenciais do app
- No Project Navigator, clique na raiz do projeto.
- Na área principal do editor, selecione o destino principal do aplicativo na lista TARGETS.
- Selecione a guia Informações na parte de cima da área do editor.
- Passe o cursor sobre a última linha na seção Propriedades de destino personalizadas do iOS e clique no botão + que aparece.

- Na coluna Chave, digite GIDClientID.
- Na coluna Valor, cole o ID do cliente que você copiou do console do Google Cloud.

- Abra o arquivo plist que você baixou do console do Google Cloud.
- Copie o valor de ID do cliente invertido.

- Expanda Tipos de URL na parte de baixo da guia Informações.
- Selecione o botão +
- Insira o ID do cliente invertido na caixa Esquemas de URL.

Agora já podemos começar a adicionar o botão de login ao app.
5. Adicionar o botão de login
Com o projeto do Xcode configurado, é hora de começar a adicionar o botão "Fazer login com o Google" ao app.
A lógica principal dessa etapa é a chamada para GIDSignIn.sharedInstance.signIn. Esse método inicia o processo de autenticação, transferindo o controle para o SDK Fazer login com o Google para apresentar o fluxo de login com o Google ao usuário.
SwiftUI
- Encontre o arquivo ContentView.swift no navegador de projetos do Xcode.
- Substitua o conteúdo do arquivo pelo seguinte texto:
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
- Encontre o arquivo ViewController.swift no navegador de projetos do Xcode.
- Substitua o conteúdo do arquivo pelo seguinte texto:
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 ?? "")")
}
}
}

Ver o botão de login
Inicie o app no simulador. O botão "Fazer login com o Google" vai aparecer, mas ainda não vai funcionar corretamente. Isso é esperado, já que você ainda precisa implementar o código para processar o redirecionamento de volta ao app depois que o usuário se autentica.
6. Personalizar o botão de login
É possível personalizar o botão padrão "Fazer login com o Google" para combinar melhor com o tema do seu app. Com o SDK Sign-in com o Google, é possível modificar o esquema de cores e o estilo do botão.
SwiftUI
O botão padrão é adicionado à página com esta linha de código:
GoogleSignInButton(action: handleSignInButton)
O GoogleSignInButton é personalizado transmitindo parâmetros ao inicializador dele. O código a seguir faz com que o botão de login apareça no modo escuro.
- Abra ContentView.swift.
- Atualize o inicializador do
GoogleSignInButtonpara conter os seguintes valores:
GoogleSignInButton(
scheme: .dark, // Options: .light, .dark, .auto
style: .standard, // Options: .standard, .wide, .icon
state: .normal, // Options: .normal, .disabled
action: handleSignInButton
).padding()

Para mais informações sobre as opções de personalização, consulte a referência do framework GoogleSignInSwift.
UIKit
O botão padrão é criado com estas linhas de código:
// Create an instance of the Sign in with Google button
let signInButton = GIDSignInButton()
// Add the button to your view
view.addSubview(signInButton)
O GIDSignInButton é personalizado definindo propriedades na instância do botão. O código a seguir faz com que o botão de login apareça no modo escuro.
- Abra ViewController.swift.
- Adicione as seguintes linhas de código imediatamente antes de adicionar o botão de login à visualização na função
viewDidLoad:
// Set the width and color of the sign-in button
signInButton.style = .standard // Options: .standard, .wide, .iconOnly
signInButton.colorScheme = .dark // Options: .dark, .light

Para mais informações sobre personalização, consulte a Referência do framework GoogleSignIn.
7. Processar o URL de redirecionamento de autenticação
Com o botão de login adicionado, a próxima etapa é processar o redirecionamento que ocorre depois que um usuário se autentica. Após a autenticação, o Google retorna um URL com um código de autorização temporário. Para concluir o processo de login, um manipulador intercepta essa URL e a transmite ao SDK Sign-in com o Google para ser trocada por um token de ID assinado (JWT).
SwiftUI
- Abra o arquivo que contém sua estrutura
App. O nome desse arquivo é baseado no seu projeto, então será algo como YourProjectNameApp.swift. - Substitua o conteúdo do arquivo pelo seguinte texto:
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
- Abra AppDelegate.swift.
- Adicione a seguinte importação à parte de cima do arquivo:
import GoogleSignIn
- Adicione a seguinte função de gerenciador de autenticação na classe
AppDelegate. Um bom lugar para colocar isso é logo após a chave de fechamento do métodoapplication(_: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
}
Depois de fazer essas mudanças, o arquivo AppDelegate.swift vai ficar assim:
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.
}
}
Testar o fluxo de login
Agora você pode testar o fluxo de login completo.
Execute o app e toque no botão de login. Depois da autenticação, o Google vai mostrar uma tela de consentimento em que você pode conceder permissão para o app acessar suas informações. Depois que você aprovar, o login será concluído, e você vai voltar ao app.
Quando o fluxo de login é concluído, o SDK Sign-in with Google armazena com segurança as credenciais do usuário no Keychain do dispositivo. Essas credenciais podem ser usadas mais tarde para permitir que um usuário permaneça conectado em inicializações subsequentes do app.
8. Adicionar um botão de logout
Agora que o login está funcionando, a próxima etapa é adicionar um botão de logout e atualizar a interface para refletir o estado de login atual do usuário. Quando um login é bem-sucedido, o SDK fornece um objeto GIDGoogleUser. Esse objeto contém uma propriedade profile com informações básicas, como o nome e o e-mail do usuário, que você vai usar para personalizar a interface.
SwiftUI
- Abra o arquivo ContentView.swift.
- Adicione uma variável de estado na parte de cima da sua struct
ContentView. Essa variável vai armazenar as informações do usuário depois que ele fizer login. Como é uma variável@State, o SwiftUI atualiza automaticamente a interface sempre que o valor dela muda:
struct ContentView: View {
@State private var user: GIDGoogleUser?
}
- Substitua o
bodyatual da sua estruturaContentViewpelo seguinteVStack. Isso vai verificar se a variável de estadousercontém um usuário. Se isso acontecer, uma mensagem de boas-vindas e um botão de sair vão aparecer. Caso contrário, o botão original "Fazer login com o Google" vai aparecer:
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()
}
}
}
- Atualize o bloco de conclusão
handleSignInButtonpara atribuirsignInResult.userà nova variáveluser. Isso é o que faz a interface mudar para a visualização conectada:
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 ?? "")")
}
}
- Adicione uma nova função
signOutà parte de baixo da structContentViewpara ser chamada pelo botão de sair:
func signOut() {
GIDSignIn.sharedInstance.signOut()
// After signing out, set the `user` state variable to `nil`.
self.user = nil
}
Inicie o app e faça login. A interface vai mudar após uma autenticação bem-sucedida.

Depois de fazer essas mudanças, o arquivo ContentView.swift vai ficar assim:
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
- Abra ViewController.swift.
- Na parte de cima do
ViewController, logo abaixo de onde você declarou osignInButton, adicione um botão de sair e um rótulo de boas-vindas:
let signOutButton = UIButton(type: .system)
let welcomeLabel = UILabel()
- Adicione a seguinte função à parte de baixo do
ViewController. Essa função vai mostrar uma interface diferente para o usuário com base no status de login dele:
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
}
}
- Na parte de baixo da função
viewDidLoad, adicione o seguinte código para incluir o rótulo de boas-vindas e o botão de sair na visualização:
// --- 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)
- Atualize a função
signInButtonTappedpara chamar o métodoUpdateUIem um login bem-sucedido:
@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)
}
}
}
- Por fim, adicione uma função
signOutButtonTappedaoViewControllerpara processar o processo de encerramento da sessão:
@objc func signOutButtonTapped() {
GIDSignIn.sharedInstance.signOut()
// Update the UI for the signed-out state.
updateUI(for: nil)
}
Inicie o app e faça login. A interface vai mudar após uma autenticação bem-sucedida.

Depois de fazer essas mudanças, o arquivo ViewController.swift vai ficar assim:
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. Restaurar o estado de login de um usuário
Para melhorar a experiência dos usuários recorrentes, a próxima etapa é restaurar o estado de login deles ao iniciar o app. A chamada de restorePreviousSignIn usa as credenciais salvas no Keychain para fazer login silenciosamente, garantindo que o usuário não precise concluir o fluxo de login todas as vezes.
SwiftUI
- Abra ContentView.swift.
- Adicione o código abaixo diretamente após o
VStackna variávelbody:
.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 ?? "")")
}
}
}
O arquivo ContentView.swift vai ficar assim:
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
- Abra ViewController.swift.
- Adicione a seguinte chamada
restorePreviousSignInao final do métodoviewDidLoad:
// 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)
}
}
}
O arquivo ViewController.swift vai ficar assim:
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)
}
}
Testar o login silencioso
Depois de fazer login, saia completamente do app e inicie-o novamente. Você vai notar que o login foi feito automaticamente, sem precisar tocar no botão.
10. Entender o token de ID
Embora o objeto GIDGoogleUser seja conveniente para personalizar a interface usando o nome e o e-mail do usuário, a parte mais importante dos dados retornados pelo SDK é o token de ID.
Este codelab usa uma ferramenta on-line para inspecionar o conteúdo do JWT. Em um app de produção, envie esse token de ID para o servidor de back-end. Seu servidor precisa verificar a integridade do token de ID e usar o JWT para fazer algo mais significativo, como criar uma nova conta na plataforma de back-end ou estabelecer uma nova sessão para o usuário.
Acessar e decodificar o token JWT
- Inicie o app.
- Abra o console do Xcode. Você vai encontrar um token de ID impresso. Ele vai ficar parecido com
eyJhbGciOiJSUzI1Ni ... Hecz6Wm4Q. - Copie o token de ID e use uma ferramenta on-line, como jwt.io (em inglês), para decodificar o JWT.
O JWT decodificado vai ficar assim:
{
"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
}
Campos de token importantes
O token de ID decodificado contém campos com finalidades diferentes. Alguns são fáceis de entender, como nome e e-mail, enquanto outros são usados pelo servidor de back-end para verificação.
O campo a seguir é especialmente importante para entender:
- sub: o campo
subé um identificador exclusivo e permanente da Conta do Google do usuário. Um usuário pode mudar o e-mail principal ou o nome, mas o ID dosubnunca muda. Isso torna o camposubo valor perfeito para usar como uma chave primária para suas contas de usuário de back-end.
Obter informações do usuário do token de ID tem mais informações sobre o significado de todos os campos do token.
11. Proteja seu app com o App Check
É altamente recomendável ativar o App Check para garantir que apenas seu app possa acessar os endpoints OAuth 2.0 do Google em nome do seu projeto. O App Check funciona verificando se as solicitações para seus serviços de back-end se originam do seu app autêntico em um dispositivo real e não adulterado.
Esta seção mostra como integrar o App Check ao seu app e configurá-lo para depuração em um simulador e para um build de produção executado em um dispositivo real.
Configuração do console
A integração do App Check ao seu aplicativo exige uma configuração única nos consoles do Google Cloud e do Firebase. Isso envolve ativar o App Check para seu cliente OAuth do iOS no console do Google Cloud, criar uma chave de API para uso com o provedor de depuração do App Check e vincular seu projeto do Google Cloud ao Firebase.
Ativar o App Check no console do Google Cloud
- Navegue até a lista de clientes associados ao seu projeto do Google Cloud.
- Selecione o ID do cliente OAuth 2.0 que você criou para seu app iOS.
- Ative o App Check em Identidade do Google para iOS.

- Clique em Salvar.
Criar uma chave de API
- Acesse a página Biblioteca de APIs do seu projeto do Google Cloud.
- Digite API Firebase App Check na barra de pesquisa.

- Selecione e ative a API Firebase App Check.
- Acesse APIs e serviços e selecione Credenciais no menu de navegação.
- Selecione Criar credenciais na parte de cima da página.

- Atribua um nome a essa chave de API.
- Selecione "Apps iOS" em Restrições de aplicativo.
- Adicione o identificador do pacote do seu app como um aplicativo aprovado.
- Selecione Restringir chave em Restrições de API.
- Selecione API Firebase App Check no menu suspenso.
- Selecione Criar.

- Copie a chave de API criada. Você vai precisar dele em outra etapa.
Adicione o Firebase ao projeto do Google Cloud
- Navegue até o Console do Firebase.
- Selecione Comece configurando um projeto do Firebase.
- Selecione Adicionar o Firebase ao projeto do Google Cloud.

- Selecione um projeto do Google Cloud no menu suspenso e continue o fluxo de inscrição.
- Selecione Adicionar Firebase.
- Quando o projeto do Firebase estiver pronto, selecione Continuar para abrir o projeto.
Integração de código do lado do cliente
Com o projeto do Google Cloud configurado para o App Check, é hora de escrever o código do lado do cliente para ativar o serviço. O provedor usado para atestado é diferente nos ambientes de produção e de depuração. Um app de produção em um dispositivo real usa o serviço App Attest integrado da Apple para provar sua autenticidade. No entanto, como o simulador do iOS não pode fornecer esse tipo de declaração, o ambiente de depuração exige um provedor de depuração especial que recebe uma chave de API.
O código a seguir processa os dois cenários usando uma diretiva do compilador para selecionar automaticamente o provedor correto no momento da build.
SwiftUI
- Abra o arquivo principal do app.
- Defina a seguinte classe
AppDelegateapós as importações e antes do atributo@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
}
}
- Substitua
"YOUR_API_KEY"no código fornecido pela chave de API que você copiou do console do Google Cloud. - Adicione a seguinte linha dentro da sua estrutura
App, logo antes da variávelbody. Isso registra a classe AppDelegate com o ciclo de vida do app, permitindo que ela responda ao lançamento do app e a outros eventos do sistema:
@UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
O arquivo principal do app vai ficar assim:
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
- Abra AppDelegate.swift.
- Atualize o método
application(_:didFinishLaunchingWithOptions:)para incluir a inicialização do 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
}
- Substitua
"YOUR_API_KEY"no código fornecido pela chave de API que você copiou do console do Google Cloud.
O arquivo AppDelegate.swift vai ficar assim:
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.
}
}
Testar o App Check no simulador
- Na barra de menus do Xcode, navegue até Product > Scheme > Edit Scheme.
- Selecione Executar no menu de navegação.
- Selecione a guia Arguments.
- Na seção Argumentos transmitidos na inicialização, selecione + e adicione -FIRDebugEnabled. Esse argumento de inicialização ativa o registro de depuração do Firebase.
- Selecione Fechar.

- Inicie o app no simulador.
- Copie o token de depuração do App Check impresso no console do Xcode.

- Acesse seu projeto no Console do Firebase.
- Expanda a seção Build no menu de navegação.
- Selecione App Check.
- Selecione a guia Apps.
- Passe o cursor sobre o app e selecione o ícone do menu de três pontos.

- Selecione Gerenciar tokens de depuração.
- Selecione Adicionar token de depuração.
- Dê um nome ao token de depuração e cole o token que você copiou antes como valor.
- Selecione Salvar para registrar seu token.

- Volte ao simulador e faça login.
Pode levar vários minutos para que as métricas apareçam no console. Depois disso, você pode confirmar se o App Check está funcionando procurando um aumento nas solicitações Verificadas em um destes dois lugares:
- Na seção "App Check" do console do Firebase, na guia "APIs".

- Na página de edição do cliente OAuth no console do Google Cloud.

Depois de monitorar as métricas do App Check do seu app e confirmar que as solicitações legítimas estão sendo verificadas, ative a aplicação do App Check. Depois de aplicado, o App Check rejeita todas as solicitações não verificadas, garantindo que apenas o tráfego do seu app autêntico possa acessar os endpoints OAuth 2.0 do Google em nome do seu projeto.
12. Outros recursos
Parabéns!
Você configurou um cliente iOS do OAuth 2.0, adicionou um botão "Fazer login com o Google" a um app iOS, aprendeu a personalizar a aparência do botão, decodificou um token de ID JWT e ativou o App Check para seu app.
Estes links podem ajudar com as próximas etapas:
- Como começar a usar o Login do Google para iOS
- Repositório do Login do Google para iOS
- Verificar um token de ID do Google
- Começar a usar o App Check para o Login do Google no iOS
- Revogar tokens de acesso e desconectar o app
- Saiba mais sobre os projetos do Google Cloud
- Métodos de autenticação da Identidade do Google
- Ativar a aplicação obrigatória do App Check