13

Ich verwende "Google Sign-In" in meiner App. Daher verwende ich die Klasse GoogleApiClient, um die Benutzer-E-Mail und den ID-Token zu erhalten, den ich für mein Backend benötige.Stille anmelden, um Token mit GoogleApiClient abzurufen

Wenn sich der Benutzer in, dann habe ich Zugang zu einer Aktivität (natürlich) und ich verwende diese Aktivität die GoogleApiClient den UI-Lifecycle Sachen behandeln zu lassen, durch den Aufruf builder.enableAutoManage (MyActivity, ...)

Das funktioniert gut.

Allerdings muss ich zu einem späteren Zeitpunkt (einige Tage später) ein neues Token bekommen (aus irgendeinem Grund werde ich hier nicht näher darauf eingehen). Ich möchte dieses Token leise ohne Benutzerinteraktion erhalten. An dem Punkt in meinem Code, an dem ich dieses neue Token benötige, habe ich jedoch keinen Zugriff auf eine Aktivitätsinstanz. Das bedeutet, dass ich nicht in der Lage bin, den oben genannten Anruf zu tätigen, d. H. "Builder.enableAutoManage". Und ich habe festgestellt, dass der stille Login nicht funktioniert, wenn ich diesen Aufruf nicht mache.

Ich habe den folgenden Code beigefügt. Sehen Sie sich jetzt die "silentLogin" -Methode an. Solange das Token, das ich als Benutzer erhalten habe, die eigentliche Anmeldung durchgeführt hat, ist es jünger als eine Stunde, dann gibt die Anweisung "pendingResult.isDone" true zurück und das zwischengespeicherte Token kann empfangen werden. Wenn das Token, das ich als Benutzer erhalten habe, die tatsächliche Anmeldung jedoch älter als eine Stunde war, wird der Aufruf "pendingResult.setResultCallback" ausgeführt, ABER die Methode "onResult" wird NIEMALS aufgerufen und ich kann keine neue abrufen Zeichen. Dieses Problem tritt nicht auf, wenn ich genau dasselbe von einer Aktivität mache (und dadurch auch den Aufruf "builder.enableAutoManage" mache).

Also weiß jemand, was ich falsch mache und noch wichtiger - wie dieses Problem zu lösen und ein neues Token ohne Zugriff auf eine Aktivität Instanz zu bekommen?

ich com.google.android.gms bin mit: Play-Dienste-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); 
      } 
     } 
    } 
} 
+0

Wenn Sie Token sagen, darf ich fragen, welche Art von Token? – zIronManBox

+0

Das Token, das ich von den Google-APIs haben möchte, ist ein ID-Token (ich denke, das ist der einzige Tokentyp, den Sie durch Aufruf von GoogleSignInAccount.getIdToken() erhalten) –

Antwort

8

ich das Problem gefunden. Ich hatte den Eindruck, dass die Funktion

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

die mGoogleApiClient für mich verbinden würde (da es ein anhängige Ergebnis zurückgibt). Das war jedoch nicht der Fall, und um die oben Ich brauche nur zu lösen, den Anruf

ConnectionResult result = mGoogleApiClient.blockingConnect(); 

am Anfang der silentLogin Methode hinzuzufügen. (Und trennen Sie dann natürlich später, und auch sicherstellen, dass der Anruf in einem Thread besteht unterscheidet sich von Hauptthread)

tada‘

22

Ja beantworten oben ist richtig. Im Allgemeinen muss jeder GoogleApiClient verbunden sein, bevor er Ihnen irgendwelche Daten zurückgeben kann. Mit enableAutoManage können Sie connect()/disconnect() während onStart()/onStop() automatisch aufrufen. Wenn Sie autoManage nicht verwenden, müssen Sie() manuell verbinden.

Und noch besser, sollten Sie in einem endgültigen Block trennen.

Angenommen, Sie sind nicht auf dem UI-Thread.

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

Und auch, Ihren Code ein wenig aufzuräumen: 1.gso von unten Konfiguration aufgebaut ist identisch mit Ihrer eingefügt Code oben:

GoogleSignInOptions gso = 
    new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) 
     .requestIdToken(SERVER_CLIENT_ID) 
     .requestEmail() 
     .build(); 
  1. Basierend auf der aktuellen Logik, addOnConnectionFailedListener/addConnectionCallbacks andere nicht als adb Protokoll helfen. Vielleicht einfach nur komplett entfernen?
+0

Vielen Dank Isabella für Ihre Antwort! –

+3

Die Google-Dokumentation schlägt wie immer spektakulär fehl. Es ist absolut unklar, ob apiClient.connect vor oder nach einer versuchten Anmeldung aufgerufen werden sollte. In der Tat denke ich, dass das neue Modell des Singens und Verbindens die Komplexität erhöht, nicht reduziert hat. Jedenfalls, danke Isabella für die Antwort, das hat mir auch geholfen! – Creos

+0

Ich denke, es ist eine ziemlich kühne Aussage zu sagen, dass Google Dokumentation immer spektakulär scheitert. – rupps