내가 구현했던 구글 소셜 로그인(One-Tap) 코드는 다음과 같다.
package us.wedemy.eggeum.android
import android.app.Activity
import android.content.IntentSender
import android.graphics.Color
import android.os.Bundle
import androidx.activity.SystemBarStyle
import androidx.activity.result.IntentSenderRequest
import androidx.activity.result.contract.ActivityResultContracts
import com.google.android.gms.auth.api.identity.BeginSignInRequest
import com.google.android.gms.auth.api.identity.Identity
import com.google.android.gms.auth.api.identity.SignInClient
import com.google.android.gms.common.api.ApiException
import dagger.hilt.android.AndroidEntryPoint
import timber.log.Timber
import us.wedemy.eggeum.android.databinding.ActivityLoginBinding
import us.wedemy.eggeum.common.ui.BaseActivity
@AndroidEntryPoint
class LoginActivity : BaseActivity() {
override val binding by lazy { ActivityLoginBinding.inflate(layoutInflater) }
override var statusBarStyle = SystemBarStyle.dark(Color.TRANSPARENT)
override var navigationBarStyle = SystemBarStyle.dark(Color.TRANSPARENT)
private lateinit var oneTapClient: SignInClient
private lateinit var signInRequest: BeginSignInRequest
private val oneTapClientResult =
registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
try {
val credential = oneTapClient.getSignInCredentialFromIntent(result.data)
val idToken = credential.googleIdToken.also { idToken ->
Timber.tag("idToken").d(idToken)
}
} catch (exception: ApiException) {
Timber.e(exception.localizedMessage)
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
initGoogleLogin()
initListener()
}
private fun initGoogleLogin() {
oneTapClient = Identity.getSignInClient(this)
signInRequest = BeginSignInRequest.builder()
.setGoogleIdTokenRequestOptions(
BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
.setSupported(true)
.setServerClientId(BuildConfig.GOOGLE_CLIENT_ID)
.setFilterByAuthorizedAccounts(true)
.build(),
)
.setAutoSelectEnabled(true)
.build()
}
private fun initListener() {
binding.cvGoogleLogin.setOnClickListener {
oneTapClient
.beginSignIn(signInRequest)
.addOnSuccessListener(this) { result ->
try {
oneTapClientResult.launch(IntentSenderRequest.Builder(result.pendingIntent.intentSender).build())
} catch (exception: IntentSender.SendIntentException) {
Timber.e("Couldn't start One Tap UI: ${exception.localizedMessage}")
}
}
.addOnFailureListener(this) { exception ->
Timber.e(exception.localizedMessage)
}
}
}
}
구글 공식 문서에는 onActivityResult() 를 사용하는 deprecated 된 방식의 코드가 아직 서술되어 있어 이 부분만 registerActivityResult 를 사용하는 방법으로 migration 하였다. 일해라 구글 너네가 deprecated 시켜놨으면서
다만 위와 같이 작성 후에 로그인을 할 경우 버튼을 클릭해도 아무런 반응이 일어나지 않는 것을 확인할 수 있는데 글의 제목과 같은 에러(로그)가 발생하는 것을 확인할 수 있었다.
16: Cannot find a matching credential
분명 google cloud platform 에서 web client id 가져와서 잘 등록해줬는데 왜 매칭되는 creadential 이 없나 계속 키의 값이 유효한지 확인해봤지만 그 부분에서 문제가 있지는 않았다.
구글링 결과 다음과 같은 해결책을 찾을 수 있었는데
본문 발췌)
setFilterByAuthorizedAccounts(false)
Case #1
I was sure I had uploaded the SHA-1 signature of my debug certificate, but that was not case.
The documentation states this:
On the Credentials page, create an Android client ID for your app if you don't already have one. You will need to specify your app's package name and SHA-1 signature.
In practice you need to go to the mentioned page and create an OAuth Client ID and get the SHA-1 with the good old keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android.
Case #2
For some reason the same error code and error message will also be used if you specify setFilterByAuthorizedAccounts(true) and you as a user don't have any Google accounts that are already authorized to sign in to your application.
As specified in the documentation linked in the question you could first use setFilterByAuthorizedAccounts(true) to help the user pick the same account as the last time and then setFilterByAuthorizedAccounts(false) to make it possible to create a new user for the app.
Case #3
The user is not logged in with any Google accounts on the device.
내 경우에는 Case 2 방법으로 해결할 수 있었다.
해당 함수의 파라미터를 true 로 설정하는 경우, 앱에 이미 인증된, 이전에 로그인한 구글 계정만 로그인할 수 있어, 한번도 인증하지 않은 경우에 위와 같은 에러가 발생하며
false 로 설정할 경우, 새로운 구글 계정도 앱에 로그인할 수 있도록 지원할 수 있다.
참고)
https://firebase.google.com/docs/auth/android/google-signin?hl=ko
https://developers.google.com/identity/one-tap/android/get-saved-credentials?hl=ko