缺少功能{name=auth_api_credentials_begin_sign_in,version=6}

Chr*_*hua 24 kotlin google-signin google-one-tap

我正在尝试对我的应用程序使用 Google 身份验证方法(一键登录)。然而,当我点击签名按钮后,我遇到了以下问题:

\n

W/GoogleApiManager:com.google.android.gms.internal.auth-api.zbaz 无法执行调用,因为它需要功能(auth_api_credentials_begin_sign_in,6)。\nD/btn\xc2\xa0click:缺少功能{name=auth_api_credentials_begin_sign_in,版本=6}。

\n

我可以知道我哪里搞砸了吗?

\n
    \n
  1. 我正在使用 MsSQL 而不是 firebase。
  2. \n
  3. 我已经创建了 OAuth 2.0 客户端。
  4. \n
  5. 我正在使用 BuildConfig 的 Web 客户端 ID(我有 Web 客户端和 Android)\nbuildConfigField : ("String", "CLIENT_ID", \'"1113838514547 -neqok16gfh5b77v6hcg33c03d0khs896.apps.googleusercontent.com"\')
  6. \n
  7. 谷歌登录按钮无法与 viewBinding 配合使用,因此我将该特定按钮切换为“findViewById”
  8. \n
\n

下面是代码:

\n
    import android.content.IntentSender\nimport android.os.Bundle\nimport android.util.Log\nimport androidx.activity.result.IntentSenderRequest\nimport androidx.activity.result.contract.ActivityResultContracts\nimport androidx.appcompat.app.AppCompatActivity\nimport com.example.myapplication.databinding.ActivitySignInBinding\nimport com.google.android.gms.auth.api.identity.BeginSignInRequest\nimport com.google.android.gms.auth.api.identity.Identity\nimport com.google.android.gms.auth.api.identity.SignInClient\nimport com.google.android.gms.common.SignInButton\nimport com.google.android.gms.common.api.ApiException\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.material.snackbar.Snackbar\n\n\nclass MainLoginActivity : AppCompatActivity() {\n\n    private var _binding: ActivitySignInBinding? = null\n    private val binding get() = _binding!!\n\n    private var sign_in_button : SignInButton?  = null\n\n    private var oneTapClient: SignInClient? = null\n    private var signUpRequest: BeginSignInRequest? = null\n    private var signInRequest: BeginSignInRequest? = null\n\n    private val oneTapResult = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()){ result ->\n        try {\n            val credential = oneTapClient?.getSignInCredentialFromIntent(result.data)\n            val idToken = credential?.googleIdToken\n            when {\n                idToken != null -> {\n                    // Got an ID token from Google. Use it to authenticate\n                    // with your backend.\n                    val msg = "idToken: $idToken"\n                    Snackbar.make(binding.root, msg, Snackbar.LENGTH_INDEFINITE).show()\n                    Log.d("one tap", msg)\n                }\n                else -> {\n                    // Shouldn\'t happen.\n                    Log.d("one tap", "No ID token!")\n                    Snackbar.make(binding.root, "No ID token!", Snackbar.LENGTH_INDEFINITE).show()\n                }\n            }\n        } catch (e: ApiException) {\n            when (e.statusCode) {\n                CommonStatusCodes.CANCELED -> {\n                    Log.d("one tap", "One-tap dialog was closed.")\n                    // Don\'t re-prompt the user.\n                    Snackbar.make(binding.root, "One-tap dialog was closed.", Snackbar.LENGTH_INDEFINITE).show()\n                }\n                CommonStatusCodes.NETWORK_ERROR -> {\n                    Log.d("one tap", "One-tap encountered a network error.")\n                    // Try again or just ignore.\n                    Snackbar.make(binding.root, "One-tap encountered a network error.", Snackbar.LENGTH_INDEFINITE).show()\n                }\n                else -> {\n                    Log.d("one tap", "Couldn\'t get credential from result." +\n                            " (${e.localizedMessage})")\n                    Snackbar.make(binding.root, "Couldn\'t get credential from result.\\" +\\n" +\n                            " (${e.localizedMessage})", Snackbar.LENGTH_INDEFINITE).show()\n                }\n            }\n        }\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        _binding = ActivitySignInBinding.inflate(layoutInflater)\n        setContentView(binding.root)\n\n        sign_in_button = findViewById(R.id.sign_in_button)\n\n        oneTapClient = Identity.getSignInClient(this)\n        signUpRequest = BeginSignInRequest.builder()\n            .setGoogleIdTokenRequestOptions(\n                BeginSignInRequest.GoogleIdTokenRequestOptions.builder()\n                    .setSupported(true)\n                    // Your server\'s client ID, not your Android client ID.\n                    .setServerClientId(BuildConfig.CLIENT_ID)\n                    // Show all accounts on the device.\n                    .setFilterByAuthorizedAccounts(false)\n                    .build())\n            .build()\n        signInRequest = BeginSignInRequest.builder()\n            .setGoogleIdTokenRequestOptions(\n                BeginSignInRequest.GoogleIdTokenRequestOptions.builder()\n                    .setSupported(true)\n                    // Your server\'s client ID, not your Android client ID.\n                    .setServerClientId(BuildConfig.CLIENT_ID)\n                    // Show all accounts on the device.\n                    .setFilterByAuthorizedAccounts(true)\n                    .build())\n            .setAutoSelectEnabled(true)\n            .build()\n\n\n       sign_in_button!!.setOnClickListener{\n            displaySignIn()\n        }\n\n\n    }\n\n\n    private fun displaySignIn(){\n        oneTapClient?.beginSignIn(signInRequest!!)\n            ?.addOnSuccessListener(this) { result ->\n                try {\n                    val ib = IntentSenderRequest.Builder(result.pendingIntent.intentSender).build()\n                    oneTapResult.launch(ib)\n                } catch (e: IntentSender.SendIntentException) {\n                    Log.e("btn click", "Couldn\'t start One Tap UI: ${e.localizedMessage}")\n                }\n            }\n            ?.addOnFailureListener(this) { e ->\n                // No Google Accounts found. Just continue presenting the signed-out UI.\n                displaySignUp()\n                Log.d("btn click", e.localizedMessage!!)\n            }\n    }\n\n    private fun displaySignUp() {\n        oneTapClient?.beginSignIn(signUpRequest!!)\n            ?.addOnSuccessListener(this) { result ->\n                try {\n                    val ib = IntentSenderRequest.Builder(result.pendingIntent.intentSender).build()\n                    oneTapResult.launch(ib)\n                } catch (e: IntentSender.SendIntentException) {\n                    Log.e("btn click", "Couldn\'t start One Tap UI: ${e.localizedMessage}")\n                }\n            }\n            ?.addOnFailureListener(this) { e ->\n                // No Google Accounts found. Just continue presenting the signed-out UI.\n                displaySignUp()\n                Log.d("btn click", e.localizedMessage!!)\n            }\n    }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n

\r\n
\r\n
    import android.content.IntentSender\nimport android.os.Bundle\nimport android.util.Log\nimport androidx.activity.result.IntentSenderRequest\nimport androidx.activity.result.contract.ActivityResultContracts\nimport androidx.appcompat.app.AppCompatActivity\nimport com.example.myapplication.databinding.ActivitySignInBinding\nimport com.google.android.gms.auth.api.identity.BeginSignInRequest\nimport com.google.android.gms.auth.api.identity.Identity\nimport com.google.android.gms.auth.api.identity.SignInClient\nimport com.google.android.gms.common.SignInButton\nimport com.google.android.gms.common.api.ApiException\nimport com.google.android.gms.common.api.CommonStatusCodes\nimport com.google.android.material.snackbar.Snackbar\n\n\nclass MainLoginActivity : AppCompatActivity() {\n\n    private var _binding: ActivitySignInBinding? = null\n    private val binding get() = _binding!!\n\n    private var sign_in_button : SignInButton?  = null\n\n    private var oneTapClient: SignInClient? = null\n    private var signUpRequest: BeginSignInRequest? = null\n    private var signInRequest: BeginSignInRequest? = null\n\n    private val oneTapResult = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()){ result ->\n        try {\n            val credential = oneTapClient?.getSignInCredentialFromIntent(result.data)\n            val idToken = credential?.googleIdToken\n            when {\n                idToken != null -> {\n                    // Got an ID token from Google. Use it to authenticate\n                    // with your backend.\n                    val msg = "idToken: $idToken"\n                    Snackbar.make(binding.root, msg, Snackbar.LENGTH_INDEFINITE).show()\n                    Log.d("one tap", msg)\n                }\n                else -> {\n                    // Shouldn\'t happen.\n                    Log.d("one tap", "No ID token!")\n                    Snackbar.make(binding.root, "No ID token!", Snackbar.LENGTH_INDEFINITE).show()\n                }\n            }\n        } catch (e: ApiException) {\n            when (e.statusCode) {\n                CommonStatusCodes.CANCELED -> {\n                    Log.d("one tap", "One-tap dialog was closed.")\n                    // Don\'t re-prompt the user.\n                    Snackbar.make(binding.root, "One-tap dialog was closed.", Snackbar.LENGTH_INDEFINITE).show()\n                }\n                CommonStatusCodes.NETWORK_ERROR -> {\n                    Log.d("one tap", "One-tap encountered a network error.")\n                    // Try again or just ignore.\n                    Snackbar.make(binding.root, "One-tap encountered a network error.", Snackbar.LENGTH_INDEFINITE).show()\n                }\n                else -> {\n                    Log.d("one tap", "Couldn\'t get credential from result." +\n                            " (${e.localizedMessage})")\n                    Snackbar.make(binding.root, "Couldn\'t get credential from result.\\" +\\n" +\n                            " (${e.localizedMessage})", Snackbar.LENGTH_INDEFINITE).show()\n                }\n            }\n        }\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        _binding = ActivitySignInBinding.inflate(layoutInflater)\n        setContentView(binding.root)\n\n        sign_in_button = findViewById(R.id.sign_in_button)\n\n        oneTapClient = Identity.getSignInClient(this)\n        signUpRequest = BeginSignInRequest.builder()\n            .setGoogleIdTokenRequestOptions(\n                BeginSignInRequest.GoogleIdTokenRequestOptions.builder()\n                    .setSupported(true)\n                    // Your server\'s client ID, not your Android client ID.\n                    .setServerClientId(BuildConfig.CLIENT_ID)\n                    // Show all accounts on the device.\n                    .setFilterByAuthorizedAccounts(false)\n                    .build())\n            .build()\n        signInRequest = BeginSignInRequest.builder()\n            .setGoogleIdTokenRequestOptions(\n                BeginSignInRequest.GoogleIdTokenRequestOptions.builder()\n                    .setSupported(true)\n                    // Your server\'s client ID, not your Android client ID.\n                    .setServerClientId(BuildConfig.CLIENT_ID)\n                    // Show all accounts on the device.\n                    .setFilterByAuthorizedAccounts(true)\n                    .build())\n            .setAutoSelectEnabled(true)\n            .build()\n\n\n       sign_in_button!!.setOnClickListener{\n            displaySignIn()\n        }\n\n\n    }\n\n\n    private fun displaySignIn(){\n        oneTapClient?.beginSignIn(signInRequest!!)\n            ?.addOnSuccessListener(this) { result ->\n                try {\n                    val ib = IntentSenderRequest.Builder(result.pendingIntent.intentSender).build()\n                    oneTapResult.launch(ib)\n                } catch (e: IntentSender.SendIntentException) {\n                    Log.e("btn click", "Couldn\'t start One Tap UI: ${e.localizedMessage}")\n                }\n            }\n            ?.addOnFailureListener(this) { e ->\n                // No Google Accounts found. Just continue presenting the signed-out UI.\n                displaySignUp()\n                Log.d("btn click", e.localizedMessage!!)\n            }\n    }\n\n    private fun displaySignUp() {\n        oneTapClient?.beginSignIn(signUpRequest!!)\n            ?.addOnSuccessListener(this) { result ->\n                try {\n                    val ib = IntentSenderRequest.Builder(result.pendingIntent.intentSender).build()\n                    oneTapResult.launch(ib)\n                } catch (e: IntentSender.SendIntentException) {\n                    Log.e("btn click", "Couldn\'t start One Tap UI: ${e.localizedMessage}")\n                }\n            }\n            ?.addOnFailureListener(this) { e ->\n                // No Google Accounts found. Just continue presenting the signed-out UI.\n                displaySignUp()\n                Log.d("btn click", e.localizedMessage!!)\n            }\n    }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n

小智 8

我在这个问题上折腾了好几天,最后Alex Mamo帮我解决了。有几件事可能导致此问题。首先,确保以下几点:

  • 用户在模拟器上登录 Google 帐户。
  • SHA-1 和 SHA-256 调试指纹均已添加到正确的项目中。
  • 正确的 google-services.json 文件位于正确的目录中。
  • web_client_id 是您的,并正确传递到必填字段中。

然后,如果没有任何变化,请尝试在真实的 Android 设备上运行该应用程序。我所说的“真实”是指已经被真人实时使用过的设备,而不仅仅是方便地坐在您旁边的演示物理设备。

如果您的应用程序仍然产生相同的错误,则说明该应用程序还存在其他一些问题,遗憾的是我无法提供帮助。

如果您的应用程序在真实设备上正常运行,则意味着您的模拟器设置不正确。尝试启动一个新的模拟器并完成新的设备配置过程(对我来说,它被称为“设置您的设备”,它作为可操作的通知栏按钮提供)。与简单地在 Android 设备上登录 Google 帐户相比,这是一个单独/不同的过程。完成后,等待十分钟并重新启动以获得良好的效果。这解决了我的问题。

希望这可以帮助!


小智 0

我在尝试使用 Android Studio 模拟器登录时遇到了同样的错误。问题是与某些插件的版本不兼容。

损坏的项目构建 gradle:

id 'com.android.application' version '7.1.3' apply false
id 'com.android.library' version '7.1.3' apply false
Run Code Online (Sandbox Code Playgroud)

使固定:

id 'com.android.application' version '7.1.2' apply false
id 'com.android.library' version '7.1.2' apply false
Run Code Online (Sandbox Code Playgroud)

此外,再次下载该google-services.json文件。它应该可以解决问题。

编辑:再次遇到这个问题,我发现这是API和模拟器版本不兼容的问题。安装具有 API 31(而不是 32)的模拟器肯定可以解决问题。