21

I am trying to use the Google authentication method (One tap sign in) for my application. However, after I clicked on the sign button, I faced the following problems:

W/GoogleApiManager: com.google.android.gms.internal.auth-api.zbaz could not execute call because it requires feature (auth_api_credentials_begin_sign_in, 6). D/btn click: Missing Feature{name=auth_api_credentials_begin_sign_in, version=6}.

May I know where have I messed up?

  1. I am using MsSQL instead of firebase.
  2. I have created the OAuth 2.0 client.
  3. I am using the Web Client ID for the BuildConfig (I have both Web Client and Android) buildConfigField : ("String", "CLIENT_ID", '"1113838514547 -neqok16gfh5b77v6hcg33c03d0khs896.apps.googleusercontent.com"')
  4. The google Sign in button was not working with viewBinding so I swapped to "findViewById" for that particular button

Below are the codes:

    import android.content.IntentSender
import android.os.Bundle
import android.util.Log
import androidx.activity.result.IntentSenderRequest
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import com.example.myapplication.databinding.ActivitySignInBinding
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.SignInButton
import com.google.android.gms.common.api.ApiException
import com.google.android.gms.common.api.CommonStatusCodes
import com.google.android.material.snackbar.Snackbar


class MainLoginActivity : AppCompatActivity() {

    private var _binding: ActivitySignInBinding? = null
    private val binding get() = _binding!!

    private var sign_in_button : SignInButton?  = null

    private var oneTapClient: SignInClient? = null
    private var signUpRequest: BeginSignInRequest? = null
    private var signInRequest: BeginSignInRequest? = null

    private val oneTapResult = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()){ result ->
        try {
            val credential = oneTapClient?.getSignInCredentialFromIntent(result.data)
            val idToken = credential?.googleIdToken
            when {
                idToken != null -> {
                    // Got an ID token from Google. Use it to authenticate
                    // with your backend.
                    val msg = "idToken: $idToken"
                    Snackbar.make(binding.root, msg, Snackbar.LENGTH_INDEFINITE).show()
                    Log.d("one tap", msg)
                }
                else -> {
                    // Shouldn't happen.
                    Log.d("one tap", "No ID token!")
                    Snackbar.make(binding.root, "No ID token!", Snackbar.LENGTH_INDEFINITE).show()
                }
            }
        } catch (e: ApiException) {
            when (e.statusCode) {
                CommonStatusCodes.CANCELED -> {
                    Log.d("one tap", "One-tap dialog was closed.")
                    // Don't re-prompt the user.
                    Snackbar.make(binding.root, "One-tap dialog was closed.", Snackbar.LENGTH_INDEFINITE).show()
                }
                CommonStatusCodes.NETWORK_ERROR -> {
                    Log.d("one tap", "One-tap encountered a network error.")
                    // Try again or just ignore.
                    Snackbar.make(binding.root, "One-tap encountered a network error.", Snackbar.LENGTH_INDEFINITE).show()
                }
                else -> {
                    Log.d("one tap", "Couldn't get credential from result." +
                            " (${e.localizedMessage})")
                    Snackbar.make(binding.root, "Couldn't get credential from result.\" +\n" +
                            " (${e.localizedMessage})", Snackbar.LENGTH_INDEFINITE).show()
                }
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        _binding = ActivitySignInBinding.inflate(layoutInflater)
        setContentView(binding.root)

        sign_in_button = findViewById(R.id.sign_in_button)

        oneTapClient = Identity.getSignInClient(this)
        signUpRequest = BeginSignInRequest.builder()
            .setGoogleIdTokenRequestOptions(
                BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
                    .setSupported(true)
                    // Your server's client ID, not your Android client ID.
                    .setServerClientId(BuildConfig.CLIENT_ID)
                    // Show all accounts on the device.
                    .setFilterByAuthorizedAccounts(false)
                    .build())
            .build()
        signInRequest = BeginSignInRequest.builder()
            .setGoogleIdTokenRequestOptions(
                BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
                    .setSupported(true)
                    // Your server's client ID, not your Android client ID.
                    .setServerClientId(BuildConfig.CLIENT_ID)
                    // Show all accounts on the device.
                    .setFilterByAuthorizedAccounts(true)
                    .build())
            .setAutoSelectEnabled(true)
            .build()


       sign_in_button!!.setOnClickListener{
            displaySignIn()
        }


    }


    private fun displaySignIn(){
        oneTapClient?.beginSignIn(signInRequest!!)
            ?.addOnSuccessListener(this) { result ->
                try {
                    val ib = IntentSenderRequest.Builder(result.pendingIntent.intentSender).build()
                    oneTapResult.launch(ib)
                } catch (e: IntentSender.SendIntentException) {
                    Log.e("btn click", "Couldn't start One Tap UI: ${e.localizedMessage}")
                }
            }
            ?.addOnFailureListener(this) { e ->
                // No Google Accounts found. Just continue presenting the signed-out UI.
                displaySignUp()
                Log.d("btn click", e.localizedMessage!!)
            }
    }

    private fun displaySignUp() {
        oneTapClient?.beginSignIn(signUpRequest!!)
            ?.addOnSuccessListener(this) { result ->
                try {
                    val ib = IntentSenderRequest.Builder(result.pendingIntent.intentSender).build()
                    oneTapResult.launch(ib)
                } catch (e: IntentSender.SendIntentException) {
                    Log.e("btn click", "Couldn't start One Tap UI: ${e.localizedMessage}")
                }
            }
            ?.addOnFailureListener(this) { e ->
                // No Google Accounts found. Just continue presenting the signed-out UI.
                displaySignUp()
                Log.d("btn click", e.localizedMessage!!)
            }
    }

}

  <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.google.android.gms.common.SignInButton
            android:id="@+id/sign_in_button"
            android:layout_width="129dp"
            android:layout_height="52dp"
            android:layout_marginStart="141dp"
            android:layout_marginTop="252dp"
            android:layout_marginEnd="141dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

5 Answers5

7

I was banging my head against the wall for a few days on this issue and finally Alex Mamo helped me solve it. A few things could have caused this issue. First, ensure the following:

  • User is logged in on a Google account on the emulator.
  • Both SHA-1 and SHA-256 debug fingerprints are added to the correct project.
  • The correct google-services.json file is in the correct directory.
  • The web_client_id is yours and passed correctly into the required fields.

Then if nothing changed, try running the app on a real Android device. By real I mean a device that has been used by real people for some real time and not just a demo physical device conveniently sitting right next you.

If your app still produces the same error, then there are some other issues with the app that I unfortunately cannot help with.

If your app functions correctly on a real device, then it means your emulator is not set up properly. Try spinning up a new emulator and going through the new device configuration process (for me it was called "Setting Up Your Device" and it was available as an actionable notification bar button). This is a separate/different process than simply signing into a Google Account on your Android device. Once complete, wait ten minutes and reboot for good measure. This solved my issue.

Hope this helps!

Endian Tribe
  • 71
  • 1
  • 2
  • Thanks for taking the time to post an answer. It will help future visitors for sure. – Alex Mamo Jul 29 '22 at 12:13
  • The "running on a real Android device" confirmed for me that the code works. A little extra: to make sure that it always works for anyone you can use the old authentication method (https://developers.google.com/identity/sign-in/android/sign-in) on the onFailure of the oneTapSignUp this will then use the old method of signing up with google as a backup – Tom Truyen Aug 23 '22 at 09:25
  • Though for me I never got the OneTap working on my emulator. I don't know what I'm doing wrong. But at least it works on my physical device :) – Tom Truyen Aug 23 '22 at 09:33
2

For me the error disappeared in the emulator after installing the Google Play services update as indicated in the screenshots below. First create an emulator that supports Google Play as "Pixel_4_API_R" or "Pixel_3a_API_28" (see screenshot 1).

Then start the emulator and open the Extended Controls window. There go to "Google Play" and select "Update" (see screenshot 2).

After clicking on the Update button I had to enter a google credential on the phone emulator. After entering the credentials and confirming a few screens the update of google play services did start automatically on one emulator and on another I had to click the update button again.

Screenshot 1 AVD creation

Screenshot 2 Fix auth_api_credentials_begin_sign_in

David
  • 355
  • 1
  • 9
0

I got the same error while trying to SignIn using my Android Studio emulator. The problem was a version incompatibility with some plugins.

Broken project build gradle:

id 'com.android.application' version '7.1.3' apply false
id 'com.android.library' version '7.1.3' apply false

Fix:

id 'com.android.application' version '7.1.2' apply false
id 'com.android.library' version '7.1.2' apply false

Furthermore, download again the google-services.json file. It should solve the problem.

Edit: got again the problem and I found out that it is a problem of incompatibility between the API and the version of the emulator. Installing an emulator with API 31 (instead of 32) definitely solved the problem.

GrayNeel
  • 11
  • 2
  • Mine were at `7.2.0`. Changed to `7.1.2`, resynced Gradle, downloaded `google-services.json` again. No change. – sirEgghead May 26 '22 at 21:02
0

In addition to the requirements mentioned by Endian Tribe in his answer, I also had to ensure the following in order to get rid of the error on my emulator:

  • Use a Google Play system image (Google APIs image didn't work for me).
  • Set a lock screen pattern or PIN.
  • Apply any pending system updates (did this via Settings -> Security -> Security/Google Play system update on Android 12).

Not sure if all 3 steps are required but that's what did the trick for me.

0

In my case I have correct firebase setup (tested before and it worked on same emulator).

Also I've done all steps with authorization in google on device, setup PIN and check for system and google play updates. Nothing changed.


To solve problem I have to manually clear data in Google app on emulator. Then auth in my app worked.

mohax
  • 4,435
  • 2
  • 38
  • 85