2

I am unable to get Google's one tap sign in implementation to work. The code runs, the button works however, the addOnSuccessListener never runs. I don't understand what the issue could be, as according to the documentation I've done everything correctly. The only information I get is that on failure of the addOnSuccessListener is a null reference error. I've used other stack overflow answers to get where I am, but none fix the issue One Tap Sign in - Activity Result with Jetpack Compose. I'm starting to believe it's with the setup on google play console and firebase, but I am unsure.

Some things have been cut out from the code for simplicity reasons.

MainActivity.kt


// Tags
private val TAG_SIGNIN = "Google Sign In"
private val TAG_FIREBASE = "Firebase backend auth"
private val TAG_GOOGLE = "Google Sign In Results"

@AndroidEntryPoint
class MainActivity2 : ComponentActivity() {

    // Google Sign in
    private lateinit var oneTapClient: SignInClient
    private lateinit var signInRequest: BeginSignInRequest
    private lateinit var signUpRequest: BeginSignInRequest

    // Firebase
    private lateinit var auth: FirebaseAuth

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Firebase Auth Instantiate
        auth = Firebase.auth

        // Google Onetap Sign in
        oneTapClient = Identity.getSignInClient(this)
        signInRequest = BeginSignInRequest.builder()
            .setGoogleIdTokenRequestOptions(
                BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
                    .setSupported(true)
                    .setServerClientId(getString(R.string.firebase_client_id))
                    .setFilterByAuthorizedAccounts(true)
                    .build())
            .setAutoSelectEnabled(true)
            .build()
        signUpRequest = BeginSignInRequest.builder()
            .setGoogleIdTokenRequestOptions(
                BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
                    .setSupported(true)
                    .setServerClientId(getString(R.string.firebase_client_id))
                    .setFilterByAuthorizedAccounts(false)
                    .build())
            .build()

        setContent {
         
            val authViewModel: LoginViewModel = viewModel()
            val authState = authViewModel.viewstate.collectAsState().value


            LoginScreen(
                activity,
                oneTapClient,
                signInRequest,
                signUpRequest,
                authViewModel,
                auth)
            }
        }
    }
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LoginScreen(
    activity: Activity,
    oneTapClient: SignInClient,
    signInRequest: BeginSignInRequest,
    signUpRequest: BeginSignInRequest,
    loginViewModel: LoginViewModel,
    auth: FirebaseAuth,
) {

    val launcher = rememberLauncherForActivityResult(
        ActivityResultContracts.StartIntentSenderForResult()
    ) { result ->
        if (result.resultCode == RESULT_OK) {
            val credential = oneTapClient.getSignInCredentialFromIntent(result.Data)
            val idToken = credential.googleIdToken

            if (idToken != null) {
                // Got an ID token from Google. Use it to authenticate
                // with your backend.

                when {
                    idToken != null -> {
                        // Got an ID token from Google. Use it to authenticate
                        // with Firebase.
                        val firebaseCredential = getCredential(idToken, null)
                        auth.signInWithCredential(firebaseCredential)
                            .addOnCompleteListener(activity) { task ->
                                if (task.isSuccessful) {
                                    // Sign in success, update UI with the signed-in user's information
                                    Log.d(TAG_FIREBASE, "signInWithCredential:success")
                                    val user = auth.currentUser
                                } else {
                                    // If sign in fails, display a message to the user.
                                    Log.w(TAG_FIREBASE,
                                        "signInWithCredential:failure",
                                        task. Exception)
                                }
                            }
                    }
                    else -> {
                        // Shouldn't happen.
                        Log.d(TAG_GOOGLE, "No ID token!")
                    }
                }
                Log.d("LOG", idToken)
            } else {
                Log.d("LOG", "Null Token")
            }
        } else {
            Log.e("Response", "${result.resultCode}")
        }
    }

    Material3AppTheme() {
        Scaffold { padding ->
            padding
            Column(
                modifier = Modifier.fillMaxSize(),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                val scope = rememberCoroutineScope()
                Surface(
                    onClick = {
                        scope.launch {
                            loginViewModel.signIn(activity, oneTapClient, signInRequest, signUpRequest, launcher)
                        }
                    },
                    color = MaterialTheme.colorScheme.onPrimary,
                    shadowElevation = 0.dp,
                    shape = RoundedCornerShape(5.dp),
                    border = BorderStroke(width = 1.dp, color = MaterialTheme.colorScheme.primaryContainer),
                ) {
                    Row(
                        modifier = Modifier
                            .padding(
                                start = 12.dp,
                                end = 16.dp,
                            ),
                        verticalAlignment = Alignment.CenterVertically,
                        horizontalArrangement = Arrangement.Center,
                    ) {

                        Icon(
                            painter = painterResource(id = R.drawable.ic_google_logo),
                            contentDescription = "SignInButton",
                            tint = androidx.compose.ui.graphics.Color.Unspecified,
                        )

                        Text(text = "Sign in with Google")
                    }
                }
            }
        }
    }
}

LoginViewModel.kt

    fun signIn(
        activity: Activity,
        oneTapClient: SignInClient,
        signInRequest: BeginSignInRequest,
        signUpRequest: BeginSignInRequest,
        launcher: ActivityResultLauncher<IntentSenderRequest>,
    ) {


        oneTapClient.beginSignIn(signInRequest)
            .addOnSuccessListener(activity) { result ->
                try {
                    val intentSenderRequest = IntentSenderRequest.Builder(result.pendingIntent.intentSender).build()
                    launcher.launch(intentSenderRequest)
                    Log.d(TAG_SIGNIN, "Started One Tap Sign In")
                } catch (e: IntentSender.SendIntentException) {
                    Log.e(TAG_SIGNIN, "Couldn't start One Tap UI: ${e.localizedMessage}")
                }
            }
            .addOnFailureListener(activity) { e ->

                e.localizedMessage?.let { Log.d(TAG_SIGNUP, "$it: non functional") }

                oneTapClient.beginSignIn(signUpRequest)
                    .addOnSuccessListener(activity) { result ->
                        try {
                            val intentSenderRequest = IntentSenderRequest.Builder(result.pendingIntent.intentSender).build()
                            launcher.launch(intentSenderRequest)
                        } catch (e: IntentSender.SendIntentException) {
                            Log.e(TAG_SIGNUP, "Couldn't start One Tap UI: ${e.localizedMessage}")
                        }
                    }
                    .addOnFailureListener(activity) { e ->
                        // No Google Accounts found. Just continue presenting the signed-out UI.
                        e.localizedMessage?.let { Log.d(TAG_SIGNUP, "$it: even less non functional") }
                    }
            }
    }
ibbs
  • 60
  • 1
  • 9
  • There are over 200 lines of code present in your question, and I cannot see something wrong at a first glance. However, if you consider at some point in time using Jetpack Compose, which I personally recommend, here is a useful [resource](https://medium.com/firebase-developers/how-to-authenticate-to-firebase-using-google-one-tap-in-jetpack-compose-60b30e621d0d) with the corresponding [repo](https://github.com/alexmamo/FirebaseSignInWithGoogle). – Alex Mamo Sep 19 '22 at 09:39
  • I am using jetpack compose. Also, I've seen your article and it seem a very complex implementation. I have used it to help with my current approach. I am hesitant to fully implement it. – ibbs Sep 19 '22 at 10:47
  • Oh, you're right. I didn't see those composable functions. The solution in the repo, it's not as complex as you think. Besides that, I think it's by far the simplest solution I could use. – Alex Mamo Sep 19 '22 at 10:52
  • I've tried following your guide and repo, what I have so far get me back to the same issue, a button that's not calling the sign in request. – ibbs Sep 19 '22 at 15:07
  • Have you tried to clone the repo? It works 100%. – Alex Mamo Sep 19 '22 at 15:08
  • No, I've tried cloning the project does not make a difference, on two devices on two different version of android and the device manager in android studio. – ibbs Sep 20 '22 at 06:24

1 Answers1

1

Turns out the ability to read is a crucial skill. The issue with this was simply that I did not read the resource well enough. I skimmed through the initial instructions on setting up the Google API's console and did not add the links to my privacy policy and terms of service in the OAuth consent screen page. The actual code worked correctly.

Also note that an account must be logged into the device for the one tap client prompt to appear. And I also had an issue where it did not work on one of my devices until a factory reset.

enter image description here

ibbs
  • 60
  • 1
  • 9