1. 시작하기 전에
인증 관리자를 사용하여 Android에서 Google 계정으로 로그인 기능을 구현하는 방법을 알아봅니다.
기본 요건
학습할 내용
- Google Cloud 프로젝트 및 OAuth 클라이언트를 만듭니다.
- 하단 시트 로그인 흐름을 구현합니다.
- 명시적 버튼 로그인 흐름을 구현합니다.
필요한 항목
- Android 스튜디오가 설치되어 있습니다.
- Android 스튜디오 및 에뮬레이터 시스템 요구사항을 충족하는 컴퓨터
- Java Development Kit (JDK)가 설치되어 있습니다.
2. Android 스튜디오 프로젝트 만들기
시작하려면 Android 스튜디오에서 새 프로젝트를 만듭니다.
- Android 스튜디오를 열고 New Project 를 클릭합니다.

- Phone and Tablet > Empty Activity 를 선택한 후 Next 를 클릭합니다.

- 프로젝트 설정을 구성합니다.
- 이름: 프로젝트 이름을 선택합니다.
- 패키지 이름: 기본값을 사용하거나 직접 선택합니다.
- 최소 SDK: 최신 안정화 버전 또는 > Android 14를 선택합니다.

- Finish를 클릭하고 초기 프로젝트 빌드가 완료될 때까지 기다립니다.

3. Google Cloud 프로젝트 설정
Google Cloud 프로젝트 만들기
- Google Cloud 콘솔로 이동하여 프로젝트를 선택하거나 만듭니다.

- API 및 서비스 > OAuth 동의 화면으로 이동합니다.

- Get started 를 클릭하고 필수 입력란을 작성합니다.
- 앱 이름: Android 앱의 이름을 사용합니다.
- User Support Email: Google 계정을 선택합니다.
- Audience: External 을 선택합니다.
- 연락처: 이메일 주소를 입력합니다.

- Google API 서비스: 사용자 데이터 정책 을 검토하고 Create 를 클릭합니다.

OAuth 클라이언트 설정
인증을 위한 클라이언트 ID를 가져오려면 Google Cloud 콘솔에서 웹 클라이언트 와 Android 클라이언트 를 모두 만들어야 합니다.
- Android 클라이언트: 앱의 패키지 이름과 SHA-1 서명을 확인하여 요청을 보호합니다.
- 웹 클라이언트: Google 계정으로 로그인 서비스의 백엔드 클라이언트 역할을 합니다.
Android OAuth 2.0 클라이언트 만들기
- Clients 페이지에서 Create Client 를 클릭하고 Application type 으로 Android 를 선택합니다.

MainActivity.kt의 1행과 일치하는 앱의 패키지 이름을 입력합니다.- SHA-1 서명을 생성합니다. Android 스튜디오 터미널을 열고 다음을 실행합니다.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 디지털 지문을 복사하여 콘솔의 SHA-1 fingerprint 필드에 붙여넣고 Create 를 클릭합니다.

웹 OAuth 2.0 클라이언트 만들기
- Create Client 를 다시 클릭하고 Application type 으로 Web Application 을 선택합니다.
- 웹 클라이언트의 이름을 지정하고 URL/Origins 필드를 비워두고 Create 를 클릭합니다.

- 확인 대화상자에서 생성된 Client ID 를 복사합니다. Kotlin 코드에서 이 ID를 사용합니다.

4. Android Virtual Device 설정
앱을 테스트하려면 실제 Android 기기 또는 Android Virtual Device (AVD)를 사용하면 됩니다.
AVD 만들기 및 실행
- Android 스튜디오에서 기기 관리도구를 열고 가상 기기 만들기 (또는 + 아이콘)를 클릭하고 Medium Phone을 선택합니다.
- 최신 안정화 버전을 시스템 이미지로 선택하고 Finish 를 클릭합니다.
- 기기 옆에 있는 Play/Run 아이콘을 클릭하여 에뮬레이터를 실행합니다.

기기에서 Google 계정에 로그인
- 에뮬레이터에서 Settings 앱을 열고 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를 검색하고 그룹 ID가com.google.android.gms인 라이브러리를 선택합니다. - OK 를 클릭하여 변경사항을 적용하고 프로젝트를 동기화합니다.

6. 하단 시트 흐름 구현

하단 시트 흐름은 Credential Manager API를 활용하여 사용자가 Android에서 Google 계정을 사용하여 앱에 로그인할 수 있는 간소화된 방법을 제공합니다. 특히 재사용자를 위해 속도와 편의성을 고려하여 설계된 이 흐름은 앱 실행 시 트리거되어야 합니다.
로그인 요청 빌드
- 시작하려면
MainActivity.kt를 열고 기본Greeting()및GreetingPreview()함수를 삭제합니다. - 3행부터 시작하는 기존 import 문 뒤에 다음 import 문을 추가합니다.
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" 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): 구성 가능한 함수가 처음 표시될 때 로그인 흐름을 즉시 트리거합니다.GetGoogleIdOption.Builder(): Google ID 토큰 요청을 구성합니다.setFilterByAuthorizedAccounts(true): 먼저 사용자가 이 앱에 이미 승인한 계정을 필터링하여 자동 로그인을 시도합니다. 이렇게 하면 재사용자의 불편함이 최소화됩니다.setNonce(...): 재생 공격을 방지하기 위해 각 요청에 대해generateSecureRandomNonce()로 생성된 보안 무작위 nonce를 전달합니다.
signIn(request, context): 요청을 실행합니다. 이전에 승인된 계정이 없다는 의미의NoCredentialException으로 실패하면 흐름이setFilterByAuthorizedAccounts(false)로 대체되어 사용자가 기기에 로그인된 Google 계정 중에서 선택할 수 있습니다.
로그인 요청하기
로그인 요청이 빌드되면 인증 관리자를 사용하여 로그인 프로세스를 완료할 수 있습니다. 요청을 실행하고 발생할 수 있는 일반적인 예외를 처리하는 signIn이라는 함수를 만듭니다.
MainActivity.kt 파일의 BottomSheet 함수 아래에 이 함수를 추가합니다.
@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): 인증 관리자 서비스가 초기화를 완료하기 전에 앱 시작 시 하단 시트가 즉시 트리거될 때 경합 상태를 방지하기 위해 잠시 일시중지합니다.- 예외 처리: 일반적인 사용자 인증 정보 오류 (예: 취소, 사용자 인증 정보 누락 또는 토큰 파싱 문제)를 포착하고 로깅하며 토스트를 사용하여 사용자 의견을 제공합니다.
하단 시트 흐름 트리거
시작 시 BottomSheet()을 호출하도록 MainActivity 클래스를 업데이트합니다. YOUR_CLIENT_ID_HERE를 웹 애플리케이션 클라이언트 ID로 바꿉니다.
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)
}
}
}
}
}
프로젝트를 저장하고 (File > Save) 애플리케이션을 실행합니다.
- 실행 버튼을 누릅니다.

- 에뮬레이터에서 앱이 실행되면 로그인 하단 시트가 표시됩니다. Continue 를 클릭하여 흐름을 테스트합니다.

- 로그인이 완료되었음을 확인하는 토스트 알림이 표시됩니다.

7. 버튼 흐름 구현

버튼 흐름은 사용자가 로그인하거나 가입할 수 있는 명시적 옵션을 제공합니다. 표준 브랜딩을 사용하면 일관된 환경을 제공할 수 있습니다. Google 계정으로 로그인 브랜딩 가이드라인을 준수하는 사전 승인된 애셋을 사용합니다.
브랜드 아이콘 추가
- 여기에서 브랜드 애셋을 다운로드하고 ZIP 파일의 압축을 풉니다.
signin-assets/Android/png@2x/neutral/android_neutral_sq_SI@2x.png를 복사합니다.- Android 스튜디오에서 파일을 res > drawable 폴더에 붙여넣고 이름을
siwg_button.png로 변경하고 OK를 클릭합니다.
버튼 흐름 코드
이 흐름은 동일한 signIn 도우미 함수를 재사용하지만 GetGoogleIdOption 대신 GetSignInWithGoogleOption을 전달합니다. 하단 시트 흐름과 달리 명시적 버튼 흐름은 저장된 사용자 인증 정보 또는 패스키를 미리 필터링하거나 자동으로 묻지 않습니다. 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: 하단 시트 흐름과 달리 명시적 버튼 흐름은 이 옵션을 사용하여 자동 필터링 없이 Google 계정을 선택하라는 메시지를 사용자에게 표시합니다.coroutineScope.launch: 버튼을 클릭하면 코루틴을 실행하여 정지signIn함수를 비동기식으로 실행합니다.Image: 브랜딩된siwg_button드로어블을 표시하고 흐름을 트리거하는 클릭 리스너를 연결합니다.
UI 레이아웃에 버튼 추가
자동 BottomSheet과 명시적 ButtonUI가 모두 세로로 정렬되어 표시되도록 MainActivity 레이아웃을 업데이트합니다.
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. 결론
수고하셨습니다 Android 인증 관리자를 사용하여 Google 계정으로 로그인 기능을 구현했습니다.
추가 리소스
전체 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
}
}