googlesigninoptions - login con google android studio
Iniciar sesiĆ³n silenciosamente para recuperar el token con GoogleApiClient (2)
Estoy usando "Google Sign-In" en mi aplicación. Por lo tanto, utilizo la clase GoogleApiClient para obtener el correo electrónico del usuario y el token de identificación que necesito para mi servidor.
Cuando el usuario inicia sesión, tengo acceso a una Actividad (por supuesto) y uso esa Actividad para permitir que GoogleApiClient maneje las cosas del ciclo de vida de la IU llamando a builder.enableAutoManage (myActivity, ...)
Esto funciona bien.
Sin embargo, en una etapa posterior (varios días después), necesito obtener una nueva ficha (por alguna razón, no voy a profundizar más aquí). Quiero obtener este token en silencio sin 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 Actividad. Eso significa que no puedo hacer la llamada mencionada anteriormente, es decir, "builder.enableAutoManage". Y he descubierto que si no hago esa llamada, el inicio de sesión silencioso no parece funcionar.
He adjuntado el siguiente código. Ahora, eche un vistazo en el método "silentLogin". Siempre que el token que recibí cuando el usuario hizo el inicio de sesión real sea inferior a una hora, la instrucción "pendingResult.isDone" devolverá verdadero y se podrá recibir el token almacenado en caché. Sin embargo, si el token que recibí cuando el usuario hizo el inicio de sesión real tiene más de una hora, entonces la llamada "pendingResult.setResultCallback" se realiza PERO EL método "onResult" NO SE LLAMA NUNCA Y no puedo obtener una nueva simbólico. Este problema no ocurre si hago exactamente lo mismo de una actividad (y con eso también hago la llamada "builder.enableAutoManage").
Entonces, ¿alguien sabe lo que estoy haciendo mal y, lo que es más importante, cómo resolver este problema y obtener un token nuevo 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 = "XXXXXXXXXXXXXXXXXXXXXXXX.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);
}
}
}
}
Encontré el problema. Estaba bajo la impresión de que la función
OptionalPendingResult<GoogleSignInResult> pendingResult = Auth.GoogleSignInApi.silentSignIn(googleApiClient);
iba a conectar el mGoogleApiClient por mí (ya que devuelve un resultado pendiente ). Sin embargo, ese no fue el caso y para resolver lo anterior solo necesitaba agregar la llamada
ConnectionResult result = mGoogleApiClient.blockingConnect();
En el inicio del método silentLogin. (y luego, por supuesto, desconecte más tarde, y también asegúrese de que la llamada se realice en un hilo diferente del hilo principal)
tada
Sí, la respuesta anterior es correcta. En general, cualquier GoogleApiClient debe estar conectado antes de que pueda devolverle cualquier información. enableAutoManage lo ayuda a llamar a connect () / disconnect () automáticamente durante onStart () / onStop (). Si no usa autoManage, necesitará conectarse () manualmente.
Y aún mejor, debes desconectar en un bloque finalmente.
Suponiendo que no estás en el hilo de la 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 un poco su código: 1. gso construido a partir de la siguiente configuración es idéntico al código pegado anterior:
GoogleSignInOptions gso =
new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(SERVER_CLIENT_ID)
.requestEmail()
.build();
- Basado en su lógica actual, addOnConnectionFailedListener / addConnectionCallbacks no ayuda más que el registro de adb. Tal vez simplemente eliminarlos por completo?