1. לפני שמתחילים
איך מטמיעים התחברות באמצעות חשבון Google ב-Android באמצעות Credential Manager
דרישות מוקדמות
מה תלמדו
- יוצרים פרויקט בענן ב-Google Cloud ולקוחות OAuth.
- מטמיעים את תהליך הכניסה בגיליון התחתון.
- מטמיעים את תהליך הכניסה המפורש באמצעות לחצן.
מה צריך
- Android Studio מותקן.
- מחשב שעומד בדרישות המערכת של Android Studio ושל האמולטור.
- Java Development Kit (JDK) מותקן.
2. יצירת פרויקט ב-Android Studio
כדי להתחיל, יוצרים פרויקט חדש ב-Android Studio:
- פותחים את Android Studio ולוחצים על New Project (פרויקט חדש).

- בוחרים באפשרות טלפון וטאבלט > פעילות ריקה ולוחצים על הבא.

- קובעים את הגדרות הפרויקט:
- שם: בוחרים שם לפרויקט.
- שם החבילה: אפשר להשתמש בשם ברירת המחדל או לבחור שם משלכם.
- גרסת ה-SDK המינימלית: בוחרים את הגרסה היציבה העדכנית ביותר או > Android 14.

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

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

- עוברים אל APIs & Services > OAuth consent screen (ממשקי API ושירותים > מסך הסכמה ל-OAuth).

- לוחצים על שנתחיל? וממלאים את שדות החובה:
- שם האפליקציה: משתמשים בשם של אפליקציית Android.
- כתובת אימייל לתמיכה במשתמשים: בוחרים את חשבון Google.
- קהל: בוחרים באפשרות חיצוני.
- פרטים ליצירת קשר: מזינים את כתובת האימייל.

- קוראים את המדיניות של Google בנושא נתוני משתמשים בשירותי API ולוחצים על יצירה.

הגדרת לקוחות OAuth
כדי לקבל את מזהי הלקוח לאימות, צריך ליצור לקוח אינטרנט ולקוח Android במסוף Google Cloud.
- לקוח Android: מאבטח את הבקשות על ידי אימות שם החבילה והחתימה מסוג SHA-1 של האפליקציה.
- לקוח אינטרנט: פועל כלקוח הקצה של שירות הכניסה באמצעות חשבון Google.
יצירת לקוח OAuth 2.0 ל-Android
- בדף Clients, לוחצים על Create Client ובוחרים באפשרות Android בתור Application type.

- מזינים את שם החבילה של האפליקציה (שם זהה לשם שמופיע בשורה 1 של
MainActivity.kt). - יוצרים חתימת SHA-1. פותחים את הטרמינל של Android Studio ומריצים את הפקודה:macOS/Linux:
Windows:keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
keytool -list -v -keystore "C:\Users\USERNAME\.android\debug.keystore" -alias androiddebugkey -storepass android -keypass android
- מעתיקים את טביעת האצבע של SHA-1 מ<b>פלט הפקודה</b>, מדביקים אותה בשדה טביעת אצבע SHA-1 במסוף ולוחצים על יצירה.

יצירת לקוח OAuth 2.0 לאינטרנט
- לוחצים שוב על Create Client ובוחרים באפשרות Web Application בתור Application type.
- נותנים שם ללקוח האינטרנט, משאירים את השדות URL/Origins (כתובת אתר/מקורות) ריקים ולוחצים על Create (יצירה).

- מעתיקים את מזהה הלקוח שנוצר מתיבת הדו-שיח לאישור. תשתמשו בזה בקוד Kotlin.

4. הגדרה של מכשיר Android וירטואלי
כדי לבדוק את האפליקציה, אפשר להשתמש במכשיר Android פיזי או במכשיר Android וירטואלי (AVD).
יצירה והרצה של ה-AVD
- ב-Android Studio, פותחים את Device Manager (ניהול מכשירים), לוחצים על Create Virtual Device (יצירת מכשיר וירטואלי) (או על הסמל +) ובוחרים באפשרות Medium Phone (טלפון בגודל בינוני).
- בוחרים את הגרסה היציבה העדכנית ביותר כקובץ אימג' של המערכת ולוחצים על סיום.
- מפעילים את האמולטור בלחיצה על הסמל הפעלה/הרצה לצד המכשיר.

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

5. הוספת יחסי תלות
מוסיפים לפרויקט את הספריות שנדרשות לאימות ולשילוב של Google ID:
- עוברים אל File > Project Structure > Dependencies > app (קובץ > מבנה הפרויקט > תלויות > אפליקציה).
- לוחצים על + > Library Dependency, מחפשים את
com.google.android.libraries.identity.googleid:googleidובוחרים את הגרסה האחרונה (למשל,1.1.1). - לוחצים שוב על + > Library Dependency, מחפשים את
play-services-authובוחרים את הספרייה עם Group IDcom.google.android.gms. - לוחצים על אישור כדי להחיל את השינויים ולסנכרן את הפרויקט.

6. הטמעה של תהליך הגיליון התחתון

תהליך הגיליון התחתון מסתמך על Credential Manager API כדי לספק למשתמשים דרך יעילה להיכנס לאפליקציה באמצעות חשבונות Google שלהם ב-Android. התהליך הזה נועד להיות מהיר ונוח, במיוחד למשתמשים חוזרים, והוא אמור להיות מופעל כשהאפליקציה מופעלת.
יצירת בקשת הכניסה
- כדי להתחיל, פותחים את
MainActivity.ktומסירים את פונקציות ברירת המחדלGreeting()ו-GreetingPreview(). - מוסיפים את הצהרות הייבוא הבאות אחרי ההצהרות הקיימות, החל משורה 3:
import android.content.Context import android.os.Build import android.util.Log import android.widget.Toast import androidx.annotation.RequiresApi import androidx.compose.foundation.Image import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.credentials.CredentialManager import androidx.credentials.CustomCredential import androidx.credentials.GetCredentialRequest import androidx.credentials.exceptions.GetCredentialCancellationException import androidx.credentials.exceptions.GetCredentialCustomException import androidx.credentials.exceptions.GetCredentialException import androidx.credentials.exceptions.NoCredentialException import com.google.android.libraries.identity.googleid.GetGoogleIdOption import com.google.android.libraries.identity.googleid.GetSignInWithGoogleOption import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential import com.google.android.libraries.identity.googleid.GoogleIdTokenParsingException import java.security.SecureRandom import java.util.Base64 import kotlinx.coroutines.delay import kotlinx.coroutines.launch const val TAG = "MainActivity" - מוסיפים את פונקציית ה-Composable הזו מתחת למחלקה
MainActivityבקובץMainActivity.kt:@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) @Composable fun BottomSheet(webClientId: String) { val context = LocalContext.current // LaunchedEffect is used to run a suspend function when the composable is first launched. LaunchedEffect(Unit) { // Create a Google ID option with filtering by authorized accounts enabled. val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder() .setFilterByAuthorizedAccounts(true) .setServerClientId(webClientId) .setNonce(generateSecureRandomNonce()) .build() // Create a credential request with the Google ID option. val request: GetCredentialRequest = GetCredentialRequest.Builder() .addCredentialOption(googleIdOption) .build() // Attempt to sign in with the created request using an authorized account val e = signIn(request, context) // If the sign-in fails with NoCredentialException, there are no authorized accounts. // In this case, we attempt to sign in again with filtering disabled. if (e is NoCredentialException) { val googleIdOptionFalse: GetGoogleIdOption = GetGoogleIdOption.Builder() .setFilterByAuthorizedAccounts(false) .setServerClientId(webClientId) .setNonce(generateSecureRandomNonce()) .build() val requestFalse: GetCredentialRequest = GetCredentialRequest.Builder() .addCredentialOption(googleIdOptionFalse) .build() //We will build out this function in a moment signIn(requestFalse, context) } } } //This function is used to generate a secure nonce to pass in with our request fun generateSecureRandomNonce(byteLength: Int = 32): String { val randomBytes = ByteArray(byteLength) SecureRandom.getInstanceStrong().nextBytes(randomBytes) return Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes) }
פירוט הקוד
-
LaunchedEffect(Unit): מפעיל את תהליך הכניסה לחשבון באופן מיידי כשהרכיב Composable מוצג בפעם הראשונה. -
GetGoogleIdOption.Builder(): הגדרת הבקשה לאסימון מזהה של Google.-
setFilterByAuthorizedAccounts(true): קודם מנסים כניסה שקטה על ידי סינון חשבונות שהמשתמש כבר אישר לאפליקציה הזו, כדי לצמצם את החיכוך למשתמשים חוזרים. -
setNonce(...): מעביר צופן חד-פעמי אקראי ומאובטח שנוצר לכל בקשה על ידיgenerateSecureRandomNonce()כדי למנוע מתקפות שידור חוזר.
-
-
signIn(request, context): מריץ את הבקשה. אם הפעולה נכשלת עםNoCredentialException(כלומר, לא קיים חשבון שאושר בעבר), התהליך חוזר ל-setFilterByAuthorizedAccounts(false)כדי לאפשר למשתמש לבחור מתוך כל חשבון Google שמחובר למכשיר.
שליחת בקשת הכניסה
אחרי שיוצרים את בקשת הכניסה, אפשר להשתמש ב-Credential Manager כדי להשלים את תהליך הכניסה. יוצרים פונקציה בשם signIn שמבצעת את הבקשה ומטפלת בחריגים נפוצים שעשויים להתרחש.
מוסיפים את הפונקציה הזו מתחת לפונקציה BottomSheet בקובץ MainActivity.kt:
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
suspend fun signIn(request: GetCredentialRequest, context: Context): Exception? {
val credentialManager = CredentialManager.create(context)
val failureMessage = "Sign in failed!"
//using delay() here helps prevent NoCredentialException when the BottomSheet Flow is triggered
//on the initial running of our app
delay(250)
return try {
// The getCredential is called to request a credential from Credential Manager.
val result = credentialManager.getCredential(
request = request,
context = context,
)
Log.i(TAG, result.toString())
val credential = result.credential
if (credential is CustomCredential &&
credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
val googleIdTokenCredential = GoogleIdTokenCredential.createFrom(credential.data)
Log.i(TAG, "Signed in as: ${googleIdTokenCredential.id}")
}
Toast.makeText(context, "Sign in successful!", Toast.LENGTH_SHORT).show()
Log.i(TAG, "(☞゚ヮ゚)☞ Sign in Successful! ☜(゚ヮ゚☜)")
null
} catch (e: GoogleIdTokenParsingException) {
Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
Log.e(TAG, failureMessage + ": Issue with parsing received GoogleIdToken", e)
e
} catch (e: NoCredentialException) {
Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
Log.e(TAG, failureMessage + ": No credentials found", e)
e
} catch (e: GetCredentialCancellationException) {
Toast.makeText(context, "Sign-in cancelled", Toast.LENGTH_SHORT).show()
Log.e(TAG, failureMessage + ": Sign-in was cancelled", e)
e
} catch (e: GetCredentialCustomException) {
Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
Log.e(TAG, failureMessage + ": Issue with custom credential request", e)
e
} catch (e: GetCredentialException) {
Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
Log.e(TAG, failureMessage + ": Failure getting credentials", e)
e
}
}
פירוט הקוד
-
credentialManager.getCredential(...): קריאה ל-Credential Manager API כדי להציג את גיליון התחתון או את תיבת הדו-שיח של בורר חשבונות המערכת. -
delay(250): מושהה לזמן קצר כדי למנוע מרוץ תהליכים כשגיליון התחתון מופעל מיד בהפעלת האפליקציה לפני ששירות Credential Manager סיים את האתחול. - טיפול בחריגים: תופס שגיאות נפוצות בפרטי הכניסה (למשל ביטול, פרטי כניסה חסרים או בעיות בניתוח האסימון) ומתעד אותן, ומספק למשתמש משוב באמצעות הודעות קצרות.
הפעלת התהליך של הגיליון התחתון
מעדכנים את המחלקה MainActivity כדי לקרוא ל-BottomSheet() בהפעלה. מחליפים את YOUR_CLIENT_ID_HERE במזהה הלקוח של אפליקציית האינטרנט:
class MainActivity : ComponentActivity() {
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//replace with your own web client ID from Google Cloud Console
val webClientId = "YOUR_CLIENT_ID_HERE"
setContent {
//ExampleTheme - this is derived from the name of the project not any added library
//e.g. if this project was named "Testing" it would be generated as TestingTheme
ExampleTheme {
Surface(
modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background,
) {
//This will trigger on launch
BottomSheet(webClientId)
}
}
}
}
}
שומרים את הפרויקט (קובץ > שמירה) ומריצים את האפליקציה:
- לוחצים על לחצן ההפעלה:

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

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

7. הטמעה של תהליך עבודה של כפתור

תהליך הכפתור מספק למשתמשים אפשרות ברורה להיכנס לחשבון או להירשם. שימוש במיתוג סטנדרטי מבטיח חוויה עקבית. להשתמש בנכסים שאושרו מראש ושעומדים בדרישות של הנחיות המיתוג של 'כניסה באמצעות חשבון Google'.
הוספת סמל המותג
- אפשר להוריד את הנכסים שקשורים למותג כאן ולחלץ את קובץ ה-ZIP.
- מעתיקים את
signin-assets/Android/png@2x/neutral/android_neutral_sq_SI@2x.png. - ב-Android Studio, מדביקים את הקובץ בתיקייה res > drawable, משנים את השם שלו ל-
siwg_button.pngולוחצים על OK.
קוד של זרימת כפתור
בתרשים הזרימה הזה נעשה שימוש חוזר בפונקציית העזר signIn, אבל במקום GetGoogleIdOption מועבר GetSignInWithGoogleOption. בניגוד לתהליך של Bottom Sheet, בתהליך של כפתור מפורש אין סינון מראש או הנחיה אוטומטית לשימוש בפרטי כניסה או במפתחות גישה שמורים. מדביקים את הפונקציה הקומפוזבילית הזו מתחת לפונקציה BottomSheet:
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
@Composable
fun ButtonUI(webClientId: String) {
val context = LocalContext.current
val coroutineScope = rememberCoroutineScope()
val onClick: () -> Unit = {
val signInWithGoogleOption: GetSignInWithGoogleOption = GetSignInWithGoogleOption
.Builder(serverClientId = webClientId)
.setNonce(generateSecureRandomNonce())
.build()
val request: GetCredentialRequest = GetCredentialRequest.Builder()
.addCredentialOption(signInWithGoogleOption)
.build()
coroutineScope.launch {
signIn(request, context)
}
}
Image(
painter = painterResource(id = R.drawable.siwg_button),
contentDescription = "",
modifier = Modifier
.fillMaxSize()
.clickable(enabled = true, onClick = onClick)
)
}
פירוט הקוד
-
GetSignInWithGoogleOption: בניגוד לתהליך של Bottom Sheet, בתהליך של לחצן מפורש נעשה שימוש באפשרות הזו כדי להציג למשתמשים בקשה לבחור את חשבון Google שלהם בלי סינון אוטומטי. -
coroutineScope.launch: מפעיל שגרת המשך (coroutine) כדי להריץ את פונקציית ההשעיהsignInבאופן אסינכרוני כשלוחצים על הכפתור. -
Image: מציג את רכיב ה-drawable של המותג ומצרף מאזין לקליקים כדי להפעיל את התהליך.siwg_button
הוספת הכפתור לפריסה של ממשק המשתמש
מעדכנים את הפריסה MainActivity כך שגם BottomSheet וגם ButtonUI יוצגו אנכית:
class MainActivity : ComponentActivity() {
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//replace with your own web client ID from Google Cloud Console
val webClientId = "YOUR_CLIENT_ID_HERE"
setContent {
//ExampleTheme - this is derived from the name of the project not any added library
//e.g. if this project was named "Testing" it would be generated as TestingTheme
ExampleTheme {
Surface(
modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background,
) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
//This will trigger on launch
BottomSheet(webClientId)
//This requires the user to press the button
ButtonUI(webClientId)
}
}
}
}
}
}
בדיקת התהליך של הלחצן
- מפעילים את האפליקציה.
- כדי לסגור את הגיליון התחתון הראשוני, לוחצים מחוץ לאזור הגיליון.
- לוחצים על הלחצן כניסה באמצעות חשבון Google כדי לפתוח את תיבת הדו-שיח לכניסה, ובוחרים את החשבון.

- מאמתים את התוצאה: בודקים את Logcat כדי לוודא שהשם או כתובת האימייל שלכם הודפסו.
8. סיכום
מעולה! הטמעת בהצלחה את הכניסה באמצעות חשבון Google באמצעות Credential Manager של Android.
מקורות מידע נוספים
- מסמכי Credential Manager ב-Android
- מדריך לפתרון בעיות ב-Credential Manager
- שאלות נפוצות בנושא Credential Manager
- תמיכה ב-StackOverflow
הקוד המלא של MainActivity.kt
לעיון, הנה הקוד המלא של MainActivity.kt:
package com.example.example
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.example.example.ui.theme.ExampleTheme
import android.content.ContentValues.TAG
import android.content.Context
import android.util.Log
import android.widget.Toast
import androidx.credentials.exceptions.GetCredentialException
import androidx.compose.foundation.clickable
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.credentials.CredentialManager
import androidx.credentials.exceptions.GetCredentialCancellationException
import androidx.credentials.exceptions.GetCredentialCustomException
import androidx.credentials.exceptions.NoCredentialException
import androidx.credentials.GetCredentialRequest
import com.google.android.libraries.identity.googleid.GetGoogleIdOption
import com.google.android.libraries.identity.googleid.GetSignInWithGoogleOption
import com.google.android.libraries.identity.googleid.GoogleIdTokenParsingException
import java.security.SecureRandom
import java.util.Base64
import kotlinx.coroutines.CoroutineScope
import androidx.compose.runtime.LaunchedEffect
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
class MainActivity : ComponentActivity() {
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//replace with your own web client ID from Google Cloud Console
val webClientId = "YOUR_CLIENT_ID_HERE"
setContent {
//ExampleTheme - this is derived from the name of the project not any added library
//e.g. if this project was named "Testing" it would be generated as TestingTheme
ExampleTheme {
Surface(
modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background,
) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
//This will trigger on launch
BottomSheet(webClientId)
//This requires the user to press the button
ButtonUI(webClientId)
}
}
}
}
}
}
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
@Composable
fun BottomSheet(webClientId: String) {
val context = LocalContext.current
// LaunchedEffect is used to run a suspend function when the composable is first launched.
LaunchedEffect(Unit) {
// Create a Google ID option with filtering by authorized accounts enabled.
val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
.setFilterByAuthorizedAccounts(true)
.setServerClientId(webClientId)
.setNonce(generateSecureRandomNonce())
.build()
// Create a credential request with the Google ID option.
val request: GetCredentialRequest = GetCredentialRequest.Builder()
.addCredentialOption(googleIdOption)
.build()
// Attempt to sign in with the created request using an authorized account
val e = signIn(request, context)
// If the sign-in fails with NoCredentialException, there are no authorized accounts.
// In this case, we attempt to sign in again with filtering disabled.
if (e is NoCredentialException) {
val googleIdOptionFalse: GetGoogleIdOption = GetGoogleIdOption.Builder()
.setFilterByAuthorizedAccounts(false)
.setServerClientId(webClientId)
.setNonce(generateSecureRandomNonce())
.build()
val requestFalse: GetCredentialRequest = GetCredentialRequest.Builder()
.addCredentialOption(googleIdOptionFalse)
.build()
signIn(requestFalse, context)
}
}
}
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
@Composable
fun ButtonUI(webClientId: String) {
val context = LocalContext.current
val coroutineScope = rememberCoroutineScope()
val onClick: () -> Unit = {
val signInWithGoogleOption: GetSignInWithGoogleOption = GetSignInWithGoogleOption
.Builder(serverClientId = webClientId)
.setNonce(generateSecureRandomNonce())
.build()
val request: GetCredentialRequest = GetCredentialRequest.Builder()
.addCredentialOption(signInWithGoogleOption)
.build()
coroutineScope.launch {
signIn(request, context)
}
}
Image(
painter = painterResource(id = R.drawable.siwg_button),
contentDescription = "",
modifier = Modifier
.fillMaxSize()
.clickable(onClick = onClick)
)
}
fun generateSecureRandomNonce(byteLength: Int = 32): String {
val randomBytes = ByteArray(byteLength)
SecureRandom.getInstanceStrong().nextBytes(randomBytes)
return Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes)
}
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
suspend fun signIn(request: GetCredentialRequest, context: Context): Exception? {
val credentialManager = CredentialManager.create(context)
val failureMessage = "Sign in failed!"
//using delay() here helps prevent NoCredentialException when the BottomSheet Flow is triggered
//on the initial running of our app
delay(250)
return try {
// The getCredential is called to request a credential from Credential Manager.
val result = credentialManager.getCredential(
request = request,
context = context,
)
Log.i(TAG, result.toString())
val credential = result.credential
if (credential is CustomCredential &&
credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
val googleIdTokenCredential = GoogleIdTokenCredential.createFrom(credential.data)
Log.i(TAG, "Signed in as: ${googleIdTokenCredential.id}")
}
Toast.makeText(context, "Sign in successful!", Toast.LENGTH_SHORT).show()
Log.i(TAG, "(☞゚ヮ゚)☞ Sign in Successful! ☜(゚ヮ゚☜)")
null
} catch (e: GoogleIdTokenParsingException) {
Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
Log.e(TAG, failureMessage + ": Issue with parsing received GoogleIdToken", e)
e
} catch (e: NoCredentialException) {
Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
Log.e(TAG, failureMessage + ": No credentials found", e)
e
} catch (e: GetCredentialCancellationException) {
Toast.makeText(context, "Sign-in cancelled", Toast.LENGTH_SHORT).show()
Log.e(TAG, failureMessage + ": Sign-in was cancelled", e)
e
} catch (e: GetCredentialCustomException) {
Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
Log.e(TAG, failureMessage + ": Issue with custom credential request", e)
e
} catch (e: GetCredentialException) {
Toast.makeText(context, failureMessage, Toast.LENGTH_SHORT).show()
Log.e(TAG, failureMessage + ": Failure getting credentials", e)
e
}
}