Scopri come implementare Accedi con Google nella tua app per Android

1. Prima di iniziare

Scopri come implementare Accedi con Google su Android utilizzando Gestore delle credenziali.

Prerequisiti

  • Conoscenza di base di Kotlin per lo sviluppo di Android.
  • Conoscenza di base di Jetpack Compose (scopri di più).

Obiettivi didattici

  • Crea un progetto Google Cloud e client OAuth.
  • Implementa il flusso di accesso del riquadro inferiore.
  • Implementa il flusso di accesso del pulsante esplicito.

Cosa serve

2. Crea un progetto Android Studio

Per iniziare, crea un nuovo progetto in Android Studio:

  1. Apri Android Studio e fai clic su New Project (Nuovo progetto). Benvenuto in Android Studio
  2. Seleziona Phone and Tablet > Empty Activity (Smartphone e tablet > Attività vuota), quindi fai clic su Next (Avanti). Progetto Android Studio
  3. Configura le impostazioni del progetto:
    • Name (Nome): scegli un nome per il progetto.
    • Nome pacchetto: utilizza il nome predefinito o scegli il tuo.
    • Minimum SDK (SDK minimo): seleziona la versione stabile più recente o > Android 14.

Progetto di configurazione di Android Studio

  1. Fai clic su Finish (Fine) e attendi il completamento della build iniziale del progetto. Progetto Android Studio creato

3. Configura il progetto Google Cloud

Crea un progetto Google Cloud

  1. Vai alla console Google Cloud e seleziona o crea un progetto. Google Cloud crea nuovo progetto
  2. Vai ad API e servizi > Schermata per il consenso OAuth. Schermata per il consenso OAuth di Google Cloud
  3. Fai clic su Inizia e compila i campi obbligatori:
    • Nome app: utilizza il nome della tua app per Android.
    • Email di assistenza utenti: seleziona il tuo Account Google.
    • Pubblico: seleziona Esterno.
    • Informazioni di contatto: inserisci il tuo indirizzo email. Informazioni sull'app GCP
  4. Esamina le Norme relative ai dati utente: servizi API di Google e fai clic su Crea. GCP Create

Configura i client OAuth

Per ottenere gli ID client per l'autenticazione, devi creare un client web e un client Android nella console Google Cloud.

  • Client Android: protegge le richieste verificando il nome del pacchetto e la firma SHA-1 dell'app.
  • Client web: funge da client di backend per il servizio Accedi con Google.

Crea un client OAuth 2.0 per Android

  1. Nella pagina Client, fai clic su Crea client e seleziona Android come Tipo di applicazione. GCP Create Clients
  2. Inserisci il nome del pacchetto dell'app (corrispondente alla riga 1 di MainActivity.kt).
  3. Genera la firma SHA-1. Apri il terminale di Android Studio ed esegui:macOS/Linux:
    keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
    
    Windows:
    keytool -list -v -keystore "C:\Users\USERNAME\.android\debug.keystore" -alias androiddebugkey -storepass android -keypass android
    
  4. Copia l'impronta SHA-1 dall'output comando, incollala nel campo Impronta SHA-1 nella console e fai clic su Crea. Dettagli del client Android

Crea un client OAuth 2.0 per il web

  1. Fai di nuovo clic su Crea client e seleziona Applicazione web come Tipo di applicazione.
  2. Assegna un nome al client web, lascia vuoti i campi URL/Origini e fai clic su Crea. Dettagli del client web
  3. Copia l'ID client generato dalla finestra di dialogo di conferma. Lo utilizzerai nel codice Kotlin. Copia ID client

4. Configura un dispositivo virtuale Android

Per testare l'app, puoi utilizzare un dispositivo Android fisico o un Android Virtual Device (AVD).

Crea ed esegui l'AVD

  1. In Android Studio, apri Device Manager (Gestione dispositivi), fai clic su Create Virtual Device (Crea dispositivo virtuale) (o sull'icona + ) e seleziona Medium Phone (Smartphone di medie dimensioni).
  2. Seleziona la versione stabile più recente come immagine di sistema e fai clic su Fine.
  3. Avvia l'emulatore facendo clic sull'icona Riproduci/Esegui accanto al dispositivo. Dispositivo in esecuzione

Accedi a un Account Google sul dispositivo

  1. Nell'emulatore, apri l'app Impostazioni e vai a Google.
  2. Fai clic su Accedi al tuo Account Google e segui le istruzioni. Accesso eseguito sul dispositivo

5. Aggiungi dipendenze

Aggiungi al progetto le librerie necessarie per l'autenticazione e l'integrazione dell'ID Google:

  1. Vai a File > Struttura progetto > Dipendenze > app.
  2. Fai clic su + > Dipendenza libreria , cerca com.google.android.libraries.identity.googleid:googleid e seleziona l'ultima versione (ad es. 1.1.1).
  3. Fai di nuovo clic su + > Dipendenza libreria , cerca play-services-auth e seleziona la libreria con l'ID gruppo com.google.android.gms.
  4. Fai clic su Ok per applicare le modifiche e sincronizzare il progetto. Dipendenze completate

6. Implementa il flusso del riquadro inferiore

Flusso del riquadro inferiore

Il flusso del riquadro inferiore utilizza l'API Credential Manager per consentire agli utenti di accedere alla tua app utilizzando i propri Account Google su Android in modo semplificato. Progettato per la velocità e la praticità, soprattutto per gli utenti che ritornano, questo flusso deve essere attivato all'avvio dell'app.

Crea la richiesta di accesso

  1. Per iniziare, apri MainActivity.kt e rimuovi le funzioni predefinite Greeting() e GreetingPreview().
  2. Aggiungi le seguenti istruzioni di importazione dopo quelle esistenti a partire dalla riga 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"
    
  3. Aggiungi questa funzione Composable sotto la classe MainActivity nel file 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)
     }
    

Analisi del codice

  • LaunchedEffect(Unit): attiva il flusso di accesso immediatamente alla prima visualizzazione del Composable.
  • GetGoogleIdOption.Builder(): configura la richiesta del token ID Google.
    • setFilterByAuthorizedAccounts(true): tenta prima un accesso silenzioso filtrando gli account che l'utente ha già autorizzato per questa app, riducendo al minimo l'attrito per gli utenti che ritornano.
    • setNonce(...): passa un nonce casuale sicuro generato per ogni richiesta da generateSecureRandomNonce() per impedire attacchi di riproduzione.
  • signIn(request, context): esegue la richiesta. Se la richiesta non va a buon fine con un'eccezione NoCredentialException (ovvero non esiste un account autorizzato in precedenza), il flusso torna a setFilterByAuthorizedAccounts(false) per consentire all'utente di selezionare uno qualsiasi degli Account Google con cui ha eseguito l'accesso sul dispositivo.

Effettua la richiesta di accesso

Una volta creata la richiesta di accesso, puoi utilizzare Gestore delle credenziali per completare la procedura di accesso. Crea una funzione denominata signIn che esegue la richiesta e gestisce le eccezioni comuni che potrebbero verificarsi.

Aggiungi questa funzione sotto la funzione BottomSheet nel file 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
    }
}

Analisi del codice

  • credentialManager.getCredential(...): chiama l'API Credential Manager per visualizzare il riquadro inferiore o la finestra di dialogo del selettore dell'account di sistema.
  • delay(250): mette in pausa brevemente per evitare una race condition quando il riquadro inferiore viene attivato immediatamente all'avvio dell'app prima che il servizio Gestore delle credenziali abbia completato l'inizializzazione.
  • Gestione delle eccezioni: rileva e registra gli errori comuni delle credenziali (ad es. annullamento, credenziali mancanti o problemi di analisi dei token) e fornisce feedback agli utenti tramite avvisi popup.

Attiva il flusso del riquadro inferiore

Aggiorna la classe MainActivity per chiamare BottomSheet() all'avvio. Sostituisci YOUR_CLIENT_ID_HERE con l'ID client dell'applicazione web:

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)
                }
            }
        }
    }
}

Salva il progetto (File > Salva) ed esegui l'applicazione:

  1. Premi il pulsante Esegui:Esegui progetto
  2. Quando l'app viene avviata sull'emulatore, dovrebbe essere visualizzato il riquadro inferiore di accesso. Fai clic su Continua per testare il flusso.Riquadro inferiore
  3. Dovrebbe essere visualizzata una notifica toast che conferma l'accesso.Riquadro inferiore riuscito

7. Implementa il flusso del pulsante

GIF del flusso dei pulsanti

Il flusso del pulsante offre agli utenti un'opzione esplicita per accedere o registrarsi. L'utilizzo del branding standard garantisce un'esperienza coerente. Utilizza asset pre-approvati conformi alle Linee guida per il branding di Accedi con Google.

Aggiungi l'icona del brand

  1. Scarica gli asset del brand qui ed estrai il file ZIP.
  2. Copia signin-assets/Android/png@2x/neutral/android_neutral_sq_SI@2x.png.
  3. In Android Studio, incolla il file nella cartella res > drawable , rinominalo in siwg_button.png e fai clic su OK. Pulsante Aggiungi

Codice del flusso del pulsante

Questo flusso riutilizza la stessa funzione helper signIn, ma passa un GetSignInWithGoogleOption anziché GetGoogleIdOption. A differenza del flusso del riquadro inferiore, il flusso del pulsante esplicito non pre-filtra né richiede automaticamente le credenziali o le passkey memorizzate. Incolla questa funzione Composable sotto la funzione 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)
    )
}

Analisi del codice

  • GetSignInWithGoogleOption: a differenza del flusso del riquadro inferiore, il flusso del pulsante esplicito utilizza questa opzione per chiedere agli utenti di selezionare il proprio Account Google senza filtro automatico.
  • coroutineScope.launch: avvia una coroutine per eseguire in modo asincrono la funzione di sospensione signIn quando si fa clic sul pulsante.
  • Image: visualizza il drawable siwg_button con il brand e collega un listener di clic per attivare il flusso.

Aggiungi il pulsante al layout dell'interfaccia utente

Aggiorna il layout MainActivity per visualizzare sia BottomSheet automatico sia ButtonUI esplicito allineati verticalmente:

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)
                    }
                }
            }
        }
    }
}

Testa il flusso del pulsante

  1. Esegui l'applicazione.
  2. Chiudi il riquadro inferiore iniziale facendo clic all'esterno dell'area del riquadro.
  3. Fai clic sul pulsante Accedi con Google per avviare la finestra di dialogo di accesso e seleziona il tuo account. Finestra di dialogo Accedi
  4. Verifica il risultato: controlla Logcat per confermare la stampa del nome utente/indirizzo email.

8. Conclusione

Complimenti! Hai implementato correttamente Accedi con Google utilizzando Android Gestore delle credenziali.

Risorse aggiuntive

Codice completo di MainActivity.kt

Di seguito è riportato il codice completo di MainActivity.kt per riferimento:

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
    }
}