Подтвердить что ты не робот

Тихий вход для получения токена с помощью GoogleApiClient

Я использую "Google Sign In" в своем приложении. Поэтому я использую класс GoogleApiClient для получения электронной почты пользователя и идентификатора, который мне нужен для моего бэкэнд.

Когда пользователь подписывается, у меня есть доступ к Управлению (конечно), и я использую это действие, чтобы позволить GoogleApiClient обрабатывать элементы жизненного цикла пользовательского интерфейса, вызывая builder.enableAutoManage(myActivity,...)

Это отлично работает.

Однако на более позднем этапе (несколько дней спустя) мне нужно получить новый токен (по какой-то причине я не буду здесь останавливаться). Я хочу получить этот токен без вмешательства пользователя. Однако, в момент моего кода, где мне нужен этот новый токен, у меня нет доступа к экземпляру Activity. Это означает, что я не могу для вызова, упомянутого выше, т.е. "builder.enableAutoManage". И я обнаружил, что если я не сделаю этот звонок, то тихий вход не работает.

Я приложил код ниже. Теперь взгляните на метод "silentLogin". Пока токен, который я получил, когда пользователь выполнил фактический вход, составляет менее одного часа, тогда выражение "pendingResult.isDone" вернет true и может быть получен кешированный токен. Однако, если токен, который я получил, когда пользователь выполнил фактический вход, составляет более одного часа, тогда выполняется вызов "pendingResult.setResultCallback", но метод "onResult" НИКОГДА НЕ ЗВОНО, и я не могу получить новый маркер. Эта проблема не возникает, если я делаю точно то же самое из действия (и этим также вызывается вызов "builder.enableAutoManage" ).

Итак, кто-нибудь знает, что я делаю неправильно и что еще важнее - как решить эту проблему и получить новый токен без доступа к экземпляру активности?

Я использую 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 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);
            }
        }
    }
}
4b9b3361

Ответ 1

Да, ответ выше правильный. В общем, любой GoogleApiClient необходимо подключить, прежде чем он сможет вернуть вам какие-либо данные. enableAutoManage позволяет вам автоматически вызвать connect()/disconnect() во время onStart()/onStop(). Если вы не используете autoManage, вам нужно будет подключиться() вручную.

И еще лучше, вы должны отключиться в блоке finally.

Предполагая, что вы не находитесь в потоке пользовательского интерфейса.

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

А также, чтобы немного очистить код: 1. gso, построенный из конфигурации ниже, идентичен вашему вставленному выше коде:

GoogleSignInOptions gso =
   new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
        .requestIdToken(SERVER_CLIENT_ID)
        .requestEmail()
        .build();
  1. Основываясь на вашей текущей логике, addOnConnectionFailedListener/addConnectionCallbacks не помогает, кроме журнала adb. Возможно, просто удалите их полностью?

Ответ 2

Я нашел проблему. У меня создалось впечатление, что функция

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

собирался подключить mGoogleApiClient для меня (поскольку он возвращает результат ожидающий). Однако это было не так, и для решения вышеизложенного мне просто нужно было добавить вызов

ConnectionResult result = mGoogleApiClient.blockingConnect();

в начале метода silentLogin. (а затем, конечно же, отключиться позже, а также убедиться, что вызов выполняется в потоке, отличном от основного потока).

тада