1. Sebelum memulai
Codelab ini memandu Anda membuat aplikasi iOS yang menerapkan Login dengan Google dan berjalan di simulator. Implementasi menggunakan SwiftUI dan UIKit disediakan.
SwiftUI adalah framework UI modern Apple untuk pengembangan aplikasi baru. Framework ini memungkinkan pembuatan antarmuka pengguna untuk semua platform Apple dari satu codebase bersama. Aplikasi ini memerlukan versi minimum iOS 13.
UIKit adalah framework UI asli dan mendasar Apple untuk iOS. Library ini menyediakan kompatibilitas mundur untuk versi iOS yang lebih lama. Hal ini menjadikannya pilihan yang baik untuk aplikasi mapan yang perlu mendukung berbagai perangkat lama.
Anda dapat mengikuti jalur untuk framework yang paling sesuai dengan kebutuhan pengembangan Anda.
Prasyarat
Yang akan Anda pelajari
- Cara membuat project Google Cloud
- Cara membuat klien OAuth di Konsol Google Cloud
- Cara menerapkan Login dengan Google untuk aplikasi iOS Anda
- Cara menyesuaikan tombol Login dengan Google
- Cara mendekode token ID
- Cara mengaktifkan App Check untuk aplikasi iOS Anda
Yang Anda butuhkan
- Xcode versi saat ini
- Komputer yang menjalankan macOS yang memenuhi persyaratan sistem untuk versi Xcode yang telah Anda instal
Codelab ini dibuat menggunakan Xcode 16.3 dengan simulator iOS 18.3. Anda harus menggunakan Xcode versi terbaru untuk pengembangan.
2. Buat project Xcode baru
- Buka Xcode dan pilih Create a new Xcode project.
- Pilih tab iOS, pilih template App, lalu klik Next.

- Di opsi project:
- Masukkan Nama Produk Anda.
- Pilih Tim Anda secara opsional.
- Masukkan ID Organisasi Anda.
- Catat ID Paket yang dibuat. Anda akan membutuhkannya nanti.
- Untuk Antarmuka, pilih salah satu:
- SwiftUI untuk aplikasi berbasis SwiftUI.
- Storyboard untuk aplikasi berbasis UIKit.
- Pilih Swift untuk Bahasa.
- Klik Berikutnya, lalu pilih lokasi untuk menyimpan project Anda.

3. Buat klien OAuth
Untuk mengizinkan aplikasi Anda berkomunikasi dengan layanan autentikasi Google, Anda perlu membuat client ID OAuth. Hal ini memerlukan project Google Cloud. Langkah-langkah berikut akan memandu Anda melalui proses pembuatan project dan client ID OAuth.
Memilih atau membuat project Google Cloud
- Buka Konsol Google Cloud, lalu pilih atau buat project. Jika Anda memilih project yang sudah ada, konsol akan otomatis mengarahkan Anda ke langkah berikutnya yang diperlukan.

- Masukkan nama untuk project Google Cloud baru Anda.
- Pilih Create.

Mengonfigurasi layar izin Anda
Jika sudah mengonfigurasi layar izin untuk project yang dipilih, Anda tidak akan diminta untuk mengonfigurasinya sekarang. Jika demikian, Anda dapat melewati bagian ini dan melanjutkan ke Membuat klien OAuth 2.0.
- Pilih Konfigurasi layar izin.

- Pilih Mulai di halaman branding.

- Di halaman konfigurasi project, isi kolom berikut:
- Informasi Aplikasi: Masukkan nama dan email dukungan pengguna untuk aplikasi Anda. Email dukungan ini akan ditampilkan secara publik agar pengguna dapat menghubungi Anda jika ada pertanyaan tentang izin mereka.
- Audiens: Pilih Eksternal.
- Informasi Kontak: Masukkan alamat email agar Google dapat menghubungi Anda terkait project Anda.
- Tinjau Layanan Google API: Kebijakan Data Pengguna.
- Klik Buat.

- Pilih halaman Klien di menu navigasi.
- Klik Buat Klien.

Buat klien OAuth 2.0
- Pilih iOS untuk Application type.
- Masukkan nama untuk klien Anda.
- Masukkan Bundle Identifier yang dibuat pada langkah terakhir.
- Masukkan ID Tim yang ditetapkan untuk tim Anda oleh Apple. Langkah ini bersifat opsional untuk saat ini, tetapi ID Tim diperlukan untuk mengaktifkan App Check nanti di codelab ini.
- Pilih Create.

- Salin Client ID dari jendela dialog, Anda akan memerlukannya nanti.
- Download file plist untuk dirujuk nanti.

4. Mengonfigurasi project Xcode
Langkah berikutnya adalah menyiapkan project Xcode agar berfungsi dengan SDK Login dengan Google. Proses ini melibatkan penambahan SDK ke project Anda sebagai dependensi dan mengonfigurasi setelan project dengan ID klien unik. ID ini memungkinkan SDK berkomunikasi secara aman dengan layanan autentikasi Google selama proses login.
Menginstal dependensi Login dengan Google
- Buka project Xcode Anda.
- Buka File > Add Package Dependencies.
- Di kotak penelusuran, masukkan URL untuk repositori Login dengan Google: https://github.com/google/GoogleSignIn-iOS

- Pilih Tambahkan Paket.
- Pilih target aplikasi utama untuk paket GoogleSignIn.
- Jika Anda menggunakan SwiftUI, pilih target aplikasi utama untuk paket GoogleSignInSwift. Jika Anda berencana menggunakan UIKit, jangan pilih target untuk paket ini.
- Pilih Tambahkan Paket.

Mengonfigurasi kredensial aplikasi Anda
- Di Project Navigator, klik root project Anda.
- Di area editor utama, pilih target aplikasi utama Anda dari daftar TARGETS.
- Pilih tab Info di bagian atas area editor.
- Arahkan kursor ke baris terakhir di bagian Custom iOS Target Properties, lalu klik tombol + yang muncul.

- Di kolom Key, ketik GIDClientID
- Di kolom Value, tempelkan client ID yang Anda salin dari Konsol Google Cloud.

- Buka file plist yang Anda download dari Konsol Google Cloud.
- Salin nilai untuk Reversed Client ID.

- Perluas URL Types di bagian bawah tab Info.
- Pilih tombol +.
- Masukkan Reversed Client ID di kotak URL Schemes.

Sekarang kita siap mulai menambahkan tombol login ke aplikasi.
5. Menambahkan tombol login
Setelah project Xcode dikonfigurasi, saatnya mulai menambahkan tombol Login dengan Google ke aplikasi.
Logika inti untuk langkah ini adalah panggilan ke GIDSignIn.sharedInstance.signIn. Metode ini memulai proses autentikasi, menyerahkan kontrol ke SDK Login dengan Google untuk menampilkan alur Login dengan Google kepada pengguna.
SwiftUI
- Temukan file ContentView.swift di Xcode Project Navigator.
- Ganti konten file ini dengan teks berikut:
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
- Temukan file ViewController.swift di Xcode Project Navigator.
- Ganti konten file ini dengan teks berikut:
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 ?? "")")
}
}
}

Melihat tombol login
Luncurkan aplikasi Anda di simulator. Anda akan melihat tombol Login dengan Google, tetapi tombol tersebut belum berfungsi dengan benar. Hal ini sudah diperkirakan, karena Anda masih perlu menerapkan kode untuk menangani pengalihan kembali ke aplikasi Anda setelah pengguna melakukan autentikasi.
6. Menyesuaikan tombol login
Anda dapat menyesuaikan tombol Login dengan Google default agar lebih sesuai dengan tema aplikasi Anda. SDK Login dengan Google memungkinkan Anda mengubah skema warna dan gaya tombol.
SwiftUI
Tombol default ditambahkan ke halaman dengan baris kode ini:
GoogleSignInButton(action: handleSignInButton)
GoogleSignInButton disesuaikan dengan meneruskan parameter ke inisialisasinya. Kode berikut akan membuat tombol login ditampilkan dalam mode gelap.
- Buka ContentView.swift
- Perbarui penginisialisasi untuk
GoogleSignInButtonagar berisi nilai berikut:
GoogleSignInButton(
scheme: .dark, // Options: .light, .dark, .auto
style: .standard, // Options: .standard, .wide, .icon
state: .normal, // Options: .normal, .disabled
action: handleSignInButton
).padding()

Untuk mengetahui informasi selengkapnya tentang opsi penyesuaian, lihat Referensi Framework GoogleSignInSwift
UIKit
Tombol default dibuat dengan baris kode berikut:
// Create an instance of the Sign in with Google button
let signInButton = GIDSignInButton()
// Add the button to your view
view.addSubview(signInButton)
GIDSignInButton disesuaikan dengan menyetel properti pada instance tombol. Kode berikut akan membuat tombol login ditampilkan dalam mode gelap.
- Buka ViewController.swift.
- Tambahkan baris kode berikut tepat sebelum menambahkan tombol login ke tampilan dalam fungsi
viewDidLoad:
// Set the width and color of the sign-in button
signInButton.style = .standard // Options: .standard, .wide, .iconOnly
signInButton.colorScheme = .dark // Options: .dark, .light

Untuk mengetahui informasi selengkapnya tentang penyesuaian, lihat Referensi Framework GoogleSignIn
7. Menangani URL pengalihan autentikasi
Setelah tombol login ditambahkan, langkah selanjutnya adalah menangani pengalihan yang terjadi setelah pengguna melakukan autentikasi. Setelah autentikasi, Google akan menampilkan URL dengan kode otorisasi sementara. Untuk menyelesaikan proses login, pengendali mencegat URL ini dan meneruskannya ke SDK Login dengan Google untuk ditukar dengan token ID (JWT) yang ditandatangani.
SwiftUI
- Buka file yang berisi struct
AppAnda. File ini diberi nama berdasarkan project Anda, jadi namanya akan seperti YourProjectNameApp.swift. - Ganti konten file ini dengan teks berikut:
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
- Buka AppDelegate.swift.
- Tambahkan impor berikut ke bagian atas file:
import GoogleSignIn
- Tambahkan fungsi pengendali autentikasi berikut di dalam class
AppDelegate. Tempat yang baik untuk menempatkannya adalah tepat setelah tanda kurung tutup metodeapplication(_: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
}
Setelah melakukan perubahan ini, file AppDelegate.swift Anda akan terlihat seperti ini:
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.
}
}
Menguji alur login
Sekarang Anda dapat menguji alur login lengkap.
Jalankan aplikasi Anda dan ketuk tombol login. Setelah Anda melakukan autentikasi, Google akan menampilkan layar izin tempat Anda dapat memberikan izin bagi aplikasi untuk mengakses informasi Anda. Setelah Anda menyetujui, login akan diselesaikan, dan Anda akan kembali ke aplikasi.
Saat alur login berhasil diselesaikan, SDK Login dengan Google akan menyimpan kredensial pengguna dengan aman di Keychain perangkat. Kredensial ini dapat digunakan nanti untuk memungkinkan pengguna tetap login pada peluncuran aplikasi berikutnya.
8. Menambahkan tombol logout
Setelah login berfungsi, langkah berikutnya adalah menambahkan tombol logout dan memperbarui UI untuk mencerminkan status login pengguna saat ini. Saat login berhasil, SDK akan menyediakan objek GIDGoogleUser. Objek ini berisi properti profile dengan informasi dasar seperti nama dan email pengguna yang akan Anda gunakan untuk mempersonalisasi UI.
SwiftUI
- Buka file ContentView.swift Anda.
- Tambahkan variabel status di bagian atas struct
ContentViewAnda. Variabel ini akan menyimpan informasi pengguna setelah mereka login. Karena merupakan variabel@State, SwiftUI akan otomatis mengupdate UI Anda setiap kali nilainya berubah:
struct ContentView: View {
@State private var user: GIDGoogleUser?
}
- Ganti
bodysaat ini dari structContentViewAnda denganVStackberikut. Tindakan ini akan memeriksa apakah variabel statususerberisi pengguna. Jika ya, halaman akan menampilkan pesan selamat datang dan tombol logout. Jika tidak, tombol Login dengan Google yang asli akan ditampilkan:
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()
}
}
}
- Perbarui blok penyelesaian
handleSignInButtonuntuk menetapkansignInResult.userke variabeluserbaru Anda. Hal inilah yang memicu UI untuk beralih ke tampilan login:
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 ?? "")")
}
}
- Tambahkan fungsi
signOutbaru ke bagian bawah structContentViewuntuk dipanggil oleh tombol logout:
func signOut() {
GIDSignIn.sharedInstance.signOut()
// After signing out, set the `user` state variable to `nil`.
self.user = nil
}
Luncurkan aplikasi dan login. Anda akan melihat perubahan UI setelah autentikasi berhasil.

Setelah melakukan perubahan ini, file ContentView.swift Anda akan terlihat seperti ini:
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
- Buka ViewController.swift.
- Di bagian atas
ViewController, tepat di bawah tempat Anda mendeklarasikansignInButton, tambahkan tombol logout dan label selamat datang:
let signOutButton = UIButton(type: .system)
let welcomeLabel = UILabel()
- Tambahkan fungsi berikut ke bagian bawah
ViewController. Fungsi ini akan menampilkan UI yang berbeda kepada pengguna berdasarkan status login mereka:
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
}
}
- Di bagian bawah fungsi
viewDidLoad, tambahkan kode berikut untuk menambahkan label selamat datang dan tombol logout ke tampilan:
// --- 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)
- Perbarui fungsi
signInButtonTappeduntuk memanggil metodeUpdateUIsaat login berhasil:
@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)
}
}
}
- Terakhir, tambahkan fungsi
signOutButtonTappedkeViewControlleruntuk menangani proses logout:
@objc func signOutButtonTapped() {
GIDSignIn.sharedInstance.signOut()
// Update the UI for the signed-out state.
updateUI(for: nil)
}
Luncurkan aplikasi dan login. Anda akan melihat perubahan UI setelah autentikasi berhasil.

Setelah melakukan perubahan ini, file ViewController.swift Anda akan terlihat seperti ini:
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. Memulihkan status login pengguna
Untuk meningkatkan pengalaman pengguna yang kembali, langkah berikutnya adalah memulihkan status login mereka saat aplikasi diluncurkan. Memanggil restorePreviousSignIn menggunakan kredensial yang disimpan di Keychain untuk login kembali pengguna secara diam-diam, sehingga memastikan mereka tidak harus menyelesaikan alur login setiap saat.
SwiftUI
- Buka ContentView.swift.
- Tambahkan kode berikut tepat setelah
VStackdi dalam variabelbody:
.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 Anda akan terlihat seperti ini:
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
- Buka ViewController.swift.
- Tambahkan panggilan
restorePreviousSignInberikut di akhir metodeviewDidLoad:
// 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)
}
}
}
File ViewController.swift Anda akan terlihat seperti ini:
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)
}
}
Menguji login otomatis
Setelah login, keluar dari aplikasi sepenuhnya dan luncurkan lagi. Anda akan melihat bahwa Anda kini otomatis login tanpa perlu mengetuk tombol.
10. Memahami token ID
Meskipun objek GIDGoogleUser berguna untuk mempersonalisasi UI menggunakan nama dan email pengguna, bagian data terpenting yang ditampilkan dari SDK adalah token ID.
Codelab ini menggunakan alat online untuk memeriksa konten JWT. Di aplikasi produksi, Anda harus mengirim token ID ini ke server backend Anda. Server Anda harus memverifikasi integritas token ID dan menggunakan JWT untuk melakukan sesuatu yang lebih bermakna, seperti membuat akun baru di platform backend Anda atau membuat sesi baru untuk pengguna.
Mengakses dan mendekode token JWT
- Luncurkan aplikasi Anda.
- Buka konsol Xcode. Anda akan melihat Token ID yang dicetak. Tampilannya akan terlihat seperti
eyJhbGciOiJSUzI1Ni ... Hecz6Wm4Q. - Salin token ID dan gunakan alat online seperti jwt.io untuk mendekode JWT.
JWT yang didekode akan terlihat seperti ini:
{
"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
}
Kolom token penting
Token ID yang didekode berisi kolom dengan tujuan yang berbeda. Meskipun beberapa di antaranya mudah dipahami, seperti nama dan email, yang lainnya digunakan oleh server backend Anda untuk verifikasi.
Kolom berikut sangat penting untuk dipahami:
- sub: Kolom
subadalah ID unik dan permanen untuk Akun Google pengguna. Pengguna dapat mengubah email atau nama utamanya, tetapi IDsub-nya tidak akan pernah berubah. Hal ini menjadikan kolomsubsebagai nilai yang sempurna untuk digunakan sebagai kunci utama bagi akun pengguna backend Anda.
Mendapatkan informasi pengguna dari token ID memiliki informasi lebih lanjut tentang arti semua kolom token.
11. Mengamankan aplikasi Anda dengan App Check
Sebaiknya aktifkan App Check untuk memastikan hanya aplikasi Anda yang dapat mengakses endpoint OAuth 2.0 Google atas nama project Anda. App Check berfungsi dengan memverifikasi bahwa permintaan ke layanan backend Anda berasal dari aplikasi asli Anda di perangkat yang nyata dan tidak dimodifikasi.
Bagian ini menunjukkan cara mengintegrasikan App Check ke dalam aplikasi Anda dan mengonfigurasinya untuk proses debug di simulator dan untuk build produksi yang berjalan di perangkat sungguhan.
Penyiapan konsol
Mengintegrasikan App Check ke dalam aplikasi Anda memerlukan penyiapan satu kali di konsol Google Cloud dan Firebase. Hal ini mencakup mengaktifkan App Check untuk klien OAuth iOS Anda di Konsol Google Cloud, membuat Kunci API untuk digunakan dengan penyedia debug App Check, dan menautkan project Google Cloud Anda ke Firebase.
Aktifkan App Check di Konsol Google Cloud
- Buka daftar Klien yang terkait dengan project Google Cloud Anda.
- Pilih client ID OAuth 2.0 yang Anda buat untuk aplikasi iOS Anda.
- Aktifkan App Check di bagian Google Identity untuk iOS

- Klik Simpan.
Membuat kunci API
- Buka halaman API Library untuk project Google Cloud Anda.
- Masukkan Firebase App Check API di kotak penelusuran.

- Pilih dan aktifkan Firebase App Check API.
- Buka API & Layanan, lalu pilih Kredensial di menu navigasi.
- Pilih Buat kredensial di bagian atas halaman.

- Tetapkan nama untuk Kunci API ini.
- Pilih aplikasi iOS di bagian Pembatasan aplikasi.
- Tambahkan ID paket untuk aplikasi Anda sebagai aplikasi yang disetujui.
- Pilih Batasi kunci di bagian Pembatasan API.
- Pilih Firebase App Check API dari menu drop-down.
- Pilih Create.

- Salin kunci API yang dibuat. Anda akan membutuhkannya di langkah berikutnya.
Menambahkan Firebase ke project Google Cloud Anda
- Buka Firebase Console.
- Pilih Mulai dengan menyiapkan project Firebase.
- Pilih Add Firebase to Google Cloud project.

- Pilih project Google Cloud dari menu drop-down dan lanjutkan proses pendaftaran.
- Pilih Add Firebase.
- Setelah project Firebase Anda siap, pilih Continue untuk membuka project.
Integrasi kode sisi klien
Setelah project Google Cloud dikonfigurasi untuk App Check, saatnya menulis kode sisi klien untuk mengaktifkannya. Penyedia yang digunakan untuk pengesahan berbeda di lingkungan produksi dan debug. Aplikasi produksi di perangkat sungguhan menggunakan layanan App Attest bawaan Apple untuk membuktikan keasliannya. Namun, karena simulator iOS tidak dapat memberikan pengesahan semacam ini, lingkungan debug memerlukan penyedia debug khusus yang meneruskan kunci API.
Kode berikut menangani kedua skenario dengan menggunakan direktif compiler untuk memilih penyedia yang benar secara otomatis pada waktu build.
SwiftUI
- Buka file aplikasi utama.
- Tentukan class
AppDelegateberikut setelah impor dan sebelum atribut@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
}
}
- Ganti
"YOUR_API_KEY"dalam kode yang diberikan dengan Kunci API yang Anda salin dari Konsol Google Cloud. - Tambahkan baris berikut di dalam struct
App, tepat sebelum variabelbody. Hal ini mendaftarkan class AppDelegate Anda dengan siklus proses aplikasi, sehingga memungkinkan class tersebut merespons peluncuran aplikasi dan peristiwa sistem lainnya:
@UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
File aplikasi utama Anda akan terlihat seperti ini:
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
- Buka AppDelegate.swift.
- Perbarui metode
application(_:didFinishLaunchingWithOptions:)agar berisi inisialisasi 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
}
- Ganti
"YOUR_API_KEY"dalam kode yang diberikan dengan Kunci API yang Anda salin dari Konsol Google Cloud.
File AppDelegate.swift Anda akan terlihat seperti ini:
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.
}
}
Menguji App Check di simulator
- Di Panel Menu Xcode, pilih Product > Scheme > Edit Scheme.
- Pilih Jalankan di menu navigasi.
- Pilih tab Arguments.
- Di bagian Arguments Passed on Launch, pilih + dan tambahkan -FIRDebugEnabled. Argumen peluncuran ini mengaktifkan logging debug Firebase.
- Pilih Tutup.

- Luncurkan aplikasi Anda di simulator.
- Salin token debug App Check yang dicetak di konsol Xcode.

- Buka project Anda di Firebase Console.
- Luaskan bagian Build di menu navigasi.
- Pilih Pemeriksaan Aplikasi.
- Pilih tab Aplikasi.
- Arahkan kursor ke aplikasi Anda, lalu pilih ikon menu tiga titik.

- Pilih Kelola token debug.
- Pilih Tambahkan token debug.
- Beri nama token debug Anda dan tempelkan token debug yang Anda salin sebelumnya untuk nilai.
- Pilih Simpan untuk mendaftarkan token Anda.

- Kembali ke simulator dan login.
Mungkin perlu waktu beberapa menit agar metrik muncul di konsol. Setelah mereka melakukannya, Anda dapat mengonfirmasi bahwa App Check berfungsi dengan mencari peningkatan permintaan Terverifikasi di salah satu dari dua tempat:
- Di bagian App Check pada Konsol Firebase, di tab API.

- Di halaman edit untuk klien OAuth Anda di Konsol Google Cloud.

Setelah memantau metrik App Check aplikasi dan mengonfirmasi bahwa permintaan yang sah sedang diverifikasi, Anda harus mengaktifkan penerapan App Check. Setelah diterapkan, App Check akan menolak semua permintaan yang tidak diverifikasi, sehingga hanya traffic dari aplikasi asli Anda yang dapat mengakses endpoint OAuth 2.0 Google atas nama project Anda.
12. Referensi lainnya
Selamat!
Anda telah mengonfigurasi klien OAuth 2.0 iOS, menambahkan tombol Login dengan Google ke aplikasi iOS, mempelajari cara menyesuaikan tampilan tombol, mendekode token ID JWT, dan mengaktifkan App Check untuk aplikasi Anda.
Link berikut dapat membantu Anda mengambil langkah berikutnya:
- Cara Memulai Login dengan Google untuk iOS
- Repositori Login dengan Google untuk iOS
- Memverifikasi token ID Google
- Mulai menggunakan App Check untuk Login dengan Google di iOS
- Mencabut token akses dan memutus koneksi aplikasi
- Pelajari lebih lanjut project Google Cloud
- Metode autentikasi Identitas Google
- Mengaktifkan penerapan App Check