Saiba como implementar o recurso Fazer login com o Google no seu app Android

1. Antes de começar

Aprenda a implementar o recurso Fazer login com o Google no Android usando o Credential Manager.

Pré-requisitos

  • Conhecimentos básicos de Kotlin para desenvolvimento Android.
  • Conhecimentos básicos do Jetpack Compose (saiba mais).

O que você vai aprender

  • Criar um projeto do Google Cloud e clientes OAuth.
  • Implementar o fluxo de login da página inferior.
  • Implementar o fluxo de login do botão explícito.

O que é necessário

2. Criar um projeto do Android Studio

Para começar, crie um novo projeto no Android Studio:

  1. Abra o Android Studio e clique em New Project. Boas-vindas ao Android Studio
  2. Selecione Phone and Tablet > Empty Activity e clique em Next. Projeto do Android Studio
  3. Configure as definições do projeto:
    • Nome: escolha um nome para o projeto.
    • Nome do pacote: use o padrão ou escolha o seu.
    • Minimum SDK: selecione a versão estável mais recente ou > Android 14.

Projeto de configuração do Android Studio

  1. Clique em Finish e aguarde a conclusão da criação inicial do projeto. Projeto do Android Studio criado

3. Configurar seu projeto do Google Cloud

Criar um projeto do Google Cloud

  1. Acesse o Console do Google Cloud e selecione ou crie um projeto. GCP: criar novo projeto
  2. Navegue até APIs & Services > tela de permissão do OAuth. Tela de permissão OAuth do GCP
  3. Clique em Get started e preencha os campos obrigatórios:
    • Nome do app: use o nome do seu app Android.
    • User Support Email: selecione sua Conta do Google.
    • Audience: selecione External.
    • Informações de contato: insira seu endereço de e-mail. Informações do app do GCP
  4. Analise a Google API Services: User Data Policy e clique em Create. Criação do GCP

Configurar clientes OAuth

Você precisa criar um cliente da Web e um cliente Android no Console do Google Cloud para receber os IDs do cliente para autenticação.

  • Cliente Android: protege as solicitações verificando o nome do pacote e a assinatura SHA-1 do app.
  • Cliente da Web: atua como o cliente de back-end do serviço Fazer login com o Google.

Criar um cliente OAuth 2.0 do Android

  1. Na página Clients, clique em Create Client e selecione Android como o Application type. Criação de clientes do GCP
  2. Insira o nome do pacote do seu app (correspondente à linha 1 do MainActivity.kt).
  3. Gere sua assinatura SHA-1. Abra o terminal do Android Studio e execute: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. Copie a impressão digital SHA-1 da saída do comando, cole-a no campo SHA-1 fingerprint no console e clique em Create. Detalhes do cliente Android

Criar um cliente OAuth 2.0 da Web

  1. Clique em Create Client novamente e selecione Web Application como o Application type.
  2. Nomeie o cliente da Web, deixe os campos de URL/origens em branco e clique em Create. Detalhes do cliente da Web
  3. Copie o Client ID gerado na caixa de diálogo de confirmação. Você vai usar isso no seu código Kotlin. Copiar ID do cliente

4. Configurar um dispositivo virtual Android

Para testar o app, você pode usar um dispositivo Android físico ou um dispositivo virtual Android (AVD).

Criar e executar o AVD

  1. No Android Studio, abra o Gerenciador de dispositivos, clique em Criar dispositivo virtual (ou no ícone +) e selecione Medium Phone.
  2. Selecione a versão estável mais recente como a imagem do sistema e clique em Finish.
  3. Inicie o emulador clicando no ícone Play/Run ao lado do dispositivo. Dispositivo em execução

Fazer login em uma Conta do Google no dispositivo

  1. No emulador, abra o app Settings e acesse Google.
  2. Clique em Fazer login na sua Conta do Google e siga as instruções. Dispositivo conectado

5. Adicionar dependências

Adicione as bibliotecas necessárias para autenticação e integração do ID do Google ao seu projeto:

  1. Acesse File > Project Structure > Dependencies > app.
  2. Clique em + > Library Dependency , pesquise com.google.android.libraries.identity.googleid:googleid e selecione a versão mais recente (por exemplo, 1.1.1).
  3. Clique em + > Library Dependency novamente, pesquise play-services-auth e selecione a biblioteca com o ID do grupo com.google.android.gms.
  4. Clique em OK para aplicar as mudanças e sincronizar seu projeto. Dependências concluídas

6. Implementar o fluxo da página inferior

Fluxo da página inferior

O fluxo da página inferior aproveita a API Credential Manager para oferecer uma maneira simplificada para os usuários fazerem login no seu app usando as Contas do Google no Android. Projetado para velocidade e conveniência, especialmente para usuários recorrentes, esse fluxo precisa ser acionado na inicialização do app.

Criar a solicitação de login

  1. Para começar, abra MainActivity.kt e remova as funções Greeting() e GreetingPreview() padrão.
  2. Adicione as seguintes declarações de importação após as existentes, começando na linha 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. Adicione esta função combinável abaixo da classe MainActivity no arquivo 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)
     }
    

Detalhamento do código

  • LaunchedEffect(Unit): aciona o fluxo de login imediatamente quando o elemento combinável é exibido pela primeira vez.
  • GetGoogleIdOption.Builder(): configura a solicitação de token de ID do Google.
    • setFilterByAuthorizedAccounts(true): primeiro tenta um login silencioso filtrando as contas que o usuário já autorizou para esse app, minimizando o atrito para usuários recorrentes.
    • setNonce(...): transmite um valor de uso único aleatório seguro gerado para cada solicitação por generateSecureRandomNonce() para evitar ataques de repetição.
  • signIn(request, context): executa a solicitação. Se falhar com uma NoCredentialException (ou seja, nenhuma conta autorizada anteriormente existe), o fluxo volta para setFilterByAuthorizedAccounts(false) para permitir que o usuário selecione qualquer Conta do Google conectada no dispositivo.

Fazer a solicitação de login

Com a solicitação de login criada, você pode usar o Gerenciador de credenciais para concluir o processo de login. Crie uma função chamada signIn que executa a solicitação e processa exceções comuns que podem ocorrer.

Adicione essa função abaixo da função BottomSheet no arquivo 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
    }
}

Detalhamento do código

  • credentialManager.getCredential(...): chama a API Credential Manager para exibir a página inferior ou a caixa de diálogo do seletor de contas do sistema.
  • delay(250): pausa brevemente para evitar uma disputa quando a página inferior é acionada imediatamente na inicialização do app antes que o serviço do Credential Manager termine de ser inicializado.
  • Processamento de exceções: captura e registra erros de credenciais comuns (por exemplo, cancelamento, credenciais ausentes ou problemas de análise de token) e fornece feedback do usuário usando avisos.

Acionar o fluxo da página inferior

Atualize sua classe MainActivity para chamar BottomSheet() na inicialização. Substitua YOUR_CLIENT_ID_HERE pelo ID do cliente do aplicativo da 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)
                }
            }
        }
    }
}

Salve o projeto (File > Save) e execute o aplicativo:

  1. Pressione o botão de execução:Executar projeto
  2. Quando o app for iniciado no emulador, a página inferior de login vai aparecer. Clique em Continue para testar o fluxo.Página inferior
  3. Uma notificação de aviso vai aparecer, confirmando que o login foi concluído.Página inferior de sucesso

7. Implementar o fluxo do botão

GIF de fluxo de botões

O fluxo do botão oferece uma opção explícita para os usuários fazerem login ou se inscreverem. O uso de branding padrão garante uma experiência consistente. Use recursos pré-aprovados que estejam em conformidade com as diretrizes de branding do recurso Fazer login com o Google.

Adicionar o ícone da marca

  1. Faça o download dos recursos da marca aqui e extraia o ZIP.
  2. Copie signin-assets/Android/png@2x/neutral/android_neutral_sq_SI@2x.png.
  3. No Android Studio, cole o arquivo na pasta res > drawable , renomeie-o para siwg_button.png e clique em OK. Adicionar botão

Código do fluxo do botão

Esse fluxo reutiliza a mesma função auxiliar signIn, mas transmite um GetSignInWithGoogleOption em vez de GetGoogleIdOption. Ao contrário do fluxo da página inferior, o fluxo do botão explícito não pré-filtra nem solicita automaticamente credenciais ou chaves de acesso armazenadas. Cole essa função combinável abaixo da função 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)
    )
}

Detalhamento do código

  • GetSignInWithGoogleOption: ao contrário do fluxo da página inferior, o fluxo do botão explícito usa essa opção para pedir aos usuários que selecionem a Conta do Google sem filtragem automática.
  • coroutineScope.launch: inicia uma corrotina para executar a função signIn de suspensão de forma assíncrona quando o botão é clicado.
  • Image: exibe o drawable siwg_button da marca e anexa um listener de cliques para acionar o fluxo.

Adicionar o botão ao layout da interface

Atualize o layout MainActivity para exibir a BottomSheet automática e a ButtonUI explícita alinhadas 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)
                    }
                }
            }
        }
    }
}

Testar o fluxo do botão

  1. Execute o app.
  2. Feche a página inferior inicial clicando fora da área da página.
  3. Clique no botão Fazer login com o Google para iniciar a caixa de diálogo de login e selecione sua conta. Caixa de diálogo de login
  4. Verifique o resultado: confira o Logcat para confirmar a impressão do seu nome de usuário/endereço de e-mail.

8. Conclusão

Parabéns! Você implementou o recurso Fazer login com o Google usando o Gerenciador de credenciais do Android.

Outros recursos

Código completo de MainActivity.kt

Confira o código completo de MainActivity.kt para referência:

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