Inicia sesión silenciosa para recuperar el token con GoogleApiClient

Estoy usando "Inicio de sesión de Google" en mi aplicación. Por lo tanto, uso la clase GoogleApiClient para obtener el correo electrónico de usuario y el token de ID que necesito para mi backend.

Cuando el usuario inicia sesión, entonces tengo acceso a una actividad (por supuesto) y uso esa actividad para permitir que el GoogleApiClient maneje las cosas del ciclo de vida de la interfaz de usuario llamando a builder.enableAutoManage (myActivity, …)

Esto funciona bien.

Sin embargo, en una etapa posterior (varios días más tarde), necesito conseguir un nuevo token (por alguna razón que no entraré aquí). Quiero obtener este token silenciosamente sin la interacción del usuario. Sin embargo, en el punto de mi código donde necesito este nuevo token, no tengo acceso a ninguna instancia de Activity. Eso significa que no soy capaz de hacer la llamada mencionada anteriormente, es decir, "builder.enableAutoManage". Y he encontrado que si no hago esa llamada, entonces el inicio de sesión silencioso no parece funcionar.

He adjuntado el código a continuación. Ahora, eche un vistazo en el método "silentLogin". Siempre y cuando el token que he recibido como el usuario hizo el signo real, es menor de una hora, entonces la declaración "pendingResult.isDone" devolverá true y el token en caché se puede recibir. Sin embargo, si el token que he recibido como el usuario hizo el inicio de sesión real, es mayor de una hora, a continuación, la llamada "pendingResult.setResultCallback" se realiza, pero el método "onResult" NUNCA LLAMADO y no puedo obtener un nuevo simbólico. Este problema no sucede si hago exactamente lo mismo de una actividad (y por eso también hago la llamada "constructor.enableAutoManage").

Entonces, ¿alguien sabe lo que estoy haciendo mal y lo más importante – cómo resolver este problema y obtener un nuevo token sin acceso a una instancia de actividad?

Estoy usando com.google.android.gms: play-services-auth: 8.4.0

package com.google.samples.quickstart.signin; import android.content.Context; import android.os.Bundle; import android.util.Log; import com.google.android.gms.auth.api.Auth; import com.google.android.gms.auth.api.signin.GoogleSignInAccount; import com.google.android.gms.auth.api.signin.GoogleSignInOptions; import com.google.android.gms.auth.api.signin.GoogleSignInResult; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.Scopes; import com.google.android.gms.common.api.GoogleApiClient; import com.google.android.gms.common.api.OptionalPendingResult; import com.google.android.gms.common.api.ResultCallback; import com.google.android.gms.common.api.Scope; /** * Use this class to login with google account using the OpenId oauth method. */ public class GoogleLoginStackOverflow { private static final String TAG = GoogleLoginIdToken.class.getName(); private static final String SERVER_CLIENT_ID = "292748398091-vn7g9iohtvb5l8371h7oqpeaaebhdaq9.apps.googleusercontent.com"; private GoogleApiClient mGoogleApiClient; private Context mContext; private GoogleLoginStackOverflow(Context appContext) { this.mContext = appContext; createGoogleClient(); } /** * Performs a silent sign in and fetch a token. * * @param appContext Application context */ public static void silentLogin(Context appContext) { GoogleLoginStackOverflow googleLoginIdToken = new GoogleLoginStackOverflow(appContext); googleLoginIdToken.silentLogin(); } private void createGoogleClient() { GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestProfile() .requestScopes(new Scope(Scopes.PROFILE)) .requestIdToken(SERVER_CLIENT_ID) .requestEmail() .build(); mGoogleApiClient = new GoogleApiClient.Builder(mContext) .addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() { @Override public void onConnectionFailed(ConnectionResult connectionResult) { System.out.println("onConnectionFailed = " + connectionResult); onSilentLoginFinished(null); } }) .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() { @Override public void onConnected(Bundle bundle) { System.out.println("onConnected bundle = " + bundle); onSilentLoginFinished(null); } @Override public void onConnectionSuspended(int i) { System.out.println("onConnectionSuspended i = " + i); onSilentLoginFinished(null); } }).addApi(Auth.GOOGLE_SIGN_IN_API, gso) .build(); } private void silentLogin() { OptionalPendingResult<GoogleSignInResult> pendingResult = Auth.GoogleSignInApi.silentSignIn(mGoogleApiClient); if (pendingResult != null) { if (pendingResult.isDone()) { // If the user's cached credentials are valid, the OptionalPendingResult will be "done" // and the GoogleSignInResult will be available instantly. Log.d(TAG, " ---------------- CACHED SIGN-IN ------------"); System.out.println("pendingResult is done = "); GoogleSignInResult signInResult = pendingResult.get(); onSilentLoginFinished(signInResult); } else { System.out.println("Setting result callback"); // If the user has not previously signed in on this device or the sign-in has expired, // this asynchronous branch will attempt to sign in the user silently. Cross-device // single sign-on will occur in this branch. pendingResult.setResultCallback(new ResultCallback<GoogleSignInResult>() { @Override public void onResult(GoogleSignInResult googleSignInResult) { System.out.println("googleSignInResult = " + googleSignInResult); onSilentLoginFinished(googleSignInResult); } }); } } else { onSilentLoginFinished(null); } } private void onSilentLoginFinished(GoogleSignInResult signInResult) { System.out.println("GoogleLoginIdToken.onSilentLoginFinished"); if (signInResult != null) { GoogleSignInAccount signInAccount = signInResult.getSignInAccount(); if (signInAccount != null) { String emailAddress = signInAccount.getEmail(); String token = signInAccount.getIdToken(); System.out.println("token = " + token); System.out.println("emailAddress = " + emailAddress); } } } } 

Sí, la respuesta anterior es correcta. En general, cualquier GoogleApiClient necesita estar conectado antes de que pueda devolverle cualquier dato. EnableAutoManage le ayuda a llamar a connect () / disconnect () automáticamente durante onStart () / onStop (). Si no utiliza autoManage, tendrá que conectarse () manualmente.

Y aún mejor, debe desconectarse en un bloque final.

Asumiendo que usted no está en el hilo de interfaz de usuario.

 try { ConnectionResult result = mGoogleApiClient.blockingConnect(); if (result.isSuccess()) { GoogleSignInResult googleSignInResult = Auth.GoogleSignInApi.silentSignIn(googleApiClient).await(); ... } } finally { mGoogleApiClient.disconnect(); } 

Y también, para limpiar su código un poco: 1. gso construido desde abajo la configuración es idéntica a su código pegado arriba:

 GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestIdToken(SERVER_CLIENT_ID) .requestEmail() .build(); 
  1. Basado en su lógica actual, addOnConnectionFailedListener / addConnectionCallbacks no ayuda que no sea el registro de adb. Tal vez simplemente eliminarlos completamente?

Encontré el problema. Tenía la impresión de que la función

 OptionalPendingResult<GoogleSignInResult> pendingResult = Auth.GoogleSignInApi.silentSignIn(googleApiClient); 

Iba a conectar el mGoogleApiClient para mí (ya que devuelve un resultado pendiente ). Sin embargo, que no era el caso y con el fin de resolver lo anterior sólo necesitaba añadir la llamada

 ConnectionResult result = mGoogleApiClient.blockingConnect(); 

En el principio del método silentLogin. (Y luego, por supuesto, desconectar más tarde, y también asegurarse de que la llamada se realiza en un hilo diferente del hilo principal)

Tada

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.