简体   繁体   中英

Google One Tap Sign In null reference

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

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.

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM