简体   繁体   中英

Google play service game signInSilently() FAILED error 'com.google.android.gms.common.api.ApiException: 4: 4 '

I am using google play services signInSilently() , but I got the error signInSilently() Failed com.google.android.gms.common.api.ApiException: 4: 4: , but I am a test user in my application. I already added SHA-1, client ID, client secret and enable sign in with google, google play game service on my firebase project. My code is below,

class SignInGGPlayBan2 : AppCompatActivity() {
    private lateinit var googleSignInClient: GoogleSignInClient
    private lateinit var auth: FirebaseAuth

    companion object {
        private val TAG = "SignInGGPlayBan2"
        private const val RC_SIGN_IN = 9001
    }

    private var btnSignIn: SignInButton? = null
    private var btnGGPlayGameSignOut: Button? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_ggplay)

        val gso = GoogleSignInOptions
            .Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN)
            .requestServerAuthCode(getString(R.string.default_web_client_id))
            .build()

        googleSignInClient = GoogleSignIn.getClient(this, gso)

        auth = FirebaseAuth.getInstance()

        btnSignIn = findViewById(R.id.btnGGPlayGame)
        btnGGPlayGameSignOut = findViewById(R.id.btnGGPlayGameSignOut)

        btnSignIn!!.setOnClickListener {
            startSignInIntent()
        }
    }

    override fun onStart() {
        super.onStart()
        val currentUser = auth.currentUser
        updateUI(currentUser)
    }

    private fun startSignInIntent() {
        val intent = googleSignInClient.signInIntent
        startActivityForResult(intent, RC_SIGN_IN)
    }

    private fun signInSilently() {
        googleSignInClient.silentSignIn().addOnCompleteListener(this) { task ->
            if (task.isSuccessful) {
                Toast.makeText(this@SignInGGPlayBan2, "Successful", Toast.LENGTH_SHORT).show()
                firebaseAuthWithPlayGames(task.result!!)
            } else {
                Log.d(TAG, "signInSilently() Failed", task.getException())
                Toast.makeText(this@SignInGGPlayBan2, "Failed", Toast.LENGTH_SHORT).show()
            }
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == RC_SIGN_IN) {
            val result = Auth.GoogleSignInApi.getSignInResultFromIntent(data)
            if (result!!.isSuccess) {
                firebaseAuthWithPlayGames(result.signInAccount!!)
                Toast.makeText(this@SignInGGPlayBan2, "Successful Activity", Toast.LENGTH_SHORT).show()
            } else {
                Toast.makeText(this@SignInGGPlayBan2, "Failed Activity", Toast.LENGTH_SHORT).show()
            }
        }

    private fun firebaseAuthWithPlayGames(acct: GoogleSignInAccount) {
        Log.d(TAG, "firebaseAuthWithPlayGames:" + acct.id!!)
        val auth = FirebaseAuth.getInstance()
        val credential = PlayGamesAuthProvider.getCredential(acct.serverAuthCode!!)
        auth.signInWithCredential(credential)
            .addOnCompleteListener(this) { task ->
                if (task.isSuccessful) {
                    Log.d(TAG, "signInWithCredential:success")
                    val user = auth.currentUser
                    updateUI(user)
                } else {
                    Log.w(TAG, "signInWithCredential:failure", task.exception)
                    Toast.makeText(baseContext, "Authentication failed.", Toast.LENGTH_SHORT).show()
                    updateUI(null)
                }
            }
    }

    override fun onResume() {
        super.onResume()
        signInSilently()
    }

    private fun updateUI(currentUser: FirebaseUser?) {
        if (currentUser != null) {
            btnGGPlayGameSignOut!!.visibility = View.VISIBLE 
        } else {
            btnGGPlayGameSignOut!!.visibility = View.INVISIBLE
        }
    }
}

error

signInSilently() Failed
    com.google.android.gms.common.api.ApiException: 4: 4: 
  at com.google.android.gms.common.internal.ApiExceptionUtil.fromStatus(com.google.android.gms:play-services-base@@17.1.0:4)
  at com.google.android.gms.common.internal.zai.zaf(com.google.android.gms:play-services-base@@17.1.0:2)
  at com.google.android.gms.common.internal.zak.onComplete(com.google.android.gms:play-services-base@@17.1.0:6)
  at com.google.android.gms.common.api.internal.BasePendingResult.zaa(com.google.android.gms:play-services-base@@17.1.0:176)
 at com.google.android.gms.common.api.internal.BasePendingResult.setResult(com.google.android.gms:play-services-base@@17.1.0:135)
 at com.google.android.gms.auth.api.signin.internal.zzi.zzc(com.google.android.gms:play-services-auth@@18.0.0:5)
 at com.google.android.gms.auth.api.signin.internal.zzs.dispatchTransaction(com.google.android.gms:play-services-auth@@18.0.0:6)
 at com.google.android.gms.internal.auth-api.zzc.onTransact(com.google.android.gms:play-services-auth@@18.0.0:13)
 at android.os.Binder.execTransact(Binder.java:565)

Manifest file

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myprojecttest">

<uses-permission android:name="android.permission.INTERNET"/>

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">

    <activity android:name=".SignInGGPlayBan2">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

</manifest>  

Please give me a solution for this problem.

I have been suffering from this for a few days. And today finally I figured it out.

Three Consoles are useful here: Firebase Console / Project Settings: https://console.firebase.google.com

Google Developer Console / Credentials: https://console.developers.google.com/apis/credentials

Linked Apps: https://play.google.com/apps/publish/

Looks like you are using firebase and the same here. And of course, we will follow the guide: https://firebase.google.com/docs/auth/android/play-games?authuser=0 . In my case, we are using Play Games Sign-in.

To fix those GMS ApiExceptions like DEVELOPER_ERROR (10) / INTERNAL_ERROR (8) / API_NOT_CONNECTED (17) / SIGN_IN_REQUIRED (4), follow this checklist below:

  1. Ignore the Gradle task signingReport , this is important, or it'll create an OAuth 2.0 Client ID automatically with your.package.name and SHA1 from ~/.android/debug.keystore which is error-prone.
  2. Create or use your own Key Store files, you can create it from Android Studio / Build / Generate Signed Bundle or APK / Create new... / Choose existing..., (here I created 2 files, one for debug and one for release, hereinafter called debug.jks and release.jks)
  3. Get the SHA1 from debug.jks using keytool -exportcert -alias YOUR_ALIAS -keystore debug.jks -list -v , paste your debug SHA1 to your Firebase Console.
    Firebase 控制台 Save the configuration and download the google-service.json to your Android Studio properly. Watch out, you only set the debug SHA1 but not the release one. Then Run your App, this process will create an OAuth 2.0 Client ID automatically with the debug SHA1. You can refresh the Google Developer Console / Credentials to check what you have done.
  4. DO NOT create OAuth 2.0 Client ID from Google Developer Console / Credentials, all IDs should create automatically from Google service Or Linked Apps.
  5. Then you should have two Client IDs on Google Developer Console / Credentials: Android client for your.package.name (auto created by Google Service) and Web client (auto created by Google Service) Check you google-service.json file, it'll contain two client_id , both must be exactly the same as Google Developer Console / Credentials.
  6. Make sure you settled in the Firebase console, the Authentication part.
  7. Now let's do Linked Apps. Just like the guide: https://firebase.google.com/docs/auth/android/play-games?authuser=0#link_your_firebase_project_to_your_play_publisher_account , but BEWARE there is a huge diff here, after clicked Authorize your app, the console try to automatically add your Google Play App Signing SHA1 as a client ID ( no the release.jks SHA1, the release.jks SHA1 is an upload key, google play will resign the APK/Bundle with its own key). Feel free to create it, and btw it's a good hobby to rename the Linked app like 'Your App Name - Google Play'. And Then refresh the Google Developer Console / Credentials to check.
  8. Let's link two more Apps, named 'Your App Name - AdHoc' with the SHA1 from release.jks and 'Your App Name - Debug' from debug.jks.
  9. Now Generate Signed Bundle or APK. Make sure your APK file signed properly. Beware that using Android studio, Run 'YOUR_PROJECT' at debug mode will sign the APK with ~/.android/debug.keystore which SHA1 is not the one you are using to create client id.
  10. ADB install the APK.

The Google Developer Console / Credentials should looks like this figure:
证书 The Linked Apps should look like this figure:
链接的应用程序

Thank you GOOGLE and my fallen hair, good luck to you.

Relative Answers:

How to sign your app using the upload key

Test Google Play Games on app signed with upload key

Testing Games Services using upload key instead of Google Play App signing key

First of all, you should put this on your AndroidManifest.xml

<meta-data android:name="com.google.android.gms.games.APP_ID"
    android:value="@string/app_id" />
<meta-data android:name="com.google.android.gms.version"
   android:value="@integer/google_play_services_version"/>

If you're using Play Games Services v2 SDK,

implementation 'com.google.android.gms:play-services-games-v2:17.0.0'

I got this error when I tried to sign-in with GoogleSignIn API and Play Games Services v2 SDK.

With v2 SDK, You can't sign-in or sign-out with GoogleSignIn API, any more. (cf. Remove sign-in and sign-out calls )

Sign-in is triggered automatically when your game is launched (for the first time), or you can trigger it manually with GamesSignInClient.signIn() . (cf. Migrate to Play Games Services Sign In v2 )

So your code could be modified like:

private void startSignInIntent() {
    PlayGames.getGamesSignInClient(this).signIn()
}

onResume and signInSilently (I renamed it checkAuthentication ) would be modified like this:

override fun onResume() {
    super.onResume()

    // Since the state of the signed in user can change when the activity is not active
    // it is recommended to try and sign in silently from when the app resumes.
    checkAuthentication()
}

private fun checkAuthentication() {
    PlayGames.getGamesSignInClient(this).isAuthenticated.addOnCompleteListener {
        val isAuthenticated = it.isSuccessful && it.result.isAuthenticated
        if (isAuthenticated) {
            // Continue with Play Games Services

            PlayGames.getPlayersClient(this).currentPlayer.addOnCompleteListener { task ->
                val displayName = if (task.isSuccessful) {
                    task.result.displayName
                } else {
                    handleException(
                        task.exception, "There was an issue communicating with players."
                    )
                    "???"
                }

                updateUI(displayName)
            }
        } else {
            // Disable your integration with Play Games Services or show a
            // login button to ask  players to sign-in. Clicking it should
            // call GamesSignInClient.signIn().

            updateUI(null)
        }
    }
}

(The above modifications are for examples. It might not be applied straight foward to your code as they are.)

I think the Google's official document about Play Games Services v2 SDK has some flaws. For example:

  1. The doc aboutSavedGames uses signInSilently still with v2 but it is obsolete (causing 'com.google.android.gms.common.api.ApiException: 4: 4 ' ).

  2. The doc about SavedGames uses GoogleSignInClient to specify the Drive scope, but it seems not necessary (just let alone with Play Games Services Sign In v2 is sufficient).

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