Как при авторизации с помощью Android Authorization API предотвратить появление всплывающего окна подтверждения разрешения каждый раз?

Я успешно вошел в систему с учетной записью Google с помощью CredentialManager и получил ServerAuthCode с помощью API авторизации.

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

Другими словами, hasResolution() всегда возвращает true.

Код части авторизации, которую я использую, выглядит следующим образом.

public class AuthorizationClient {
    static final int ACTIVITY_RESULT_IS_NOT_OK = 1;
    static final int EMPTY_SERVER_AUTH_CODE = 2;

    public static void authorize
        (AuthorizationListener listener, String clientId, boolean refreshToken, String[] scopes) {
        if (IntentRunnerActivity.isInitialized())
            authorizeInternal(listener, clientId, refreshToken, scopes);
        else
            IntentRunnerActivity.initialize(() -> authorizeInternal(listener, clientId, refreshToken, scopes));
    }

    static void authorizeInternal
        (AuthorizationListener listener, String clientId, boolean refreshToken, String[] scopes) {
        try {
            List<Scope> requestedScopes = new ArrayList<>();
            requestedScopes.add(new Scope("email"));
            if (scopes != null) for (String scope : scopes) requestedScopes.add(new Scope(scope));

            AuthorizationRequest authorizationRequest = new AuthorizationRequest.Builder()
                .requestOfflineAccess(clientId, refreshToken)
                .setRequestedScopes(requestedScopes)
                .build();

            Identity.getAuthorizationClient(UnityActivity.get())
                .authorize(authorizationRequest)
                .addOnSuccessListener(r -> {
                    if (r.hasResolution()) {
                        IntentRunnerActivity.run(r.getPendingIntent(), activityResult -> {
                            if (activityResult.getResultCode() == Activity.RESULT_OK) {
                                try {
                                    handleAuthorizationResult(listener,
                                        Identity.getAuthorizationClient(UnityActivity.get())
                                            .getAuthorizationResultFromIntent(activityResult.getData()));
                                } catch (ApiException e) {
                                    onException(listener, e);
                                }
                            } else listener.OnFail(ACTIVITY_RESULT_IS_NOT_OK);
                        });
                    } else handleAuthorizationResult(listener, r);
                })
                .addOnFailureListener(e -> onException(listener, e));
        } catch (Exception e) {
            onException(listener, e);
        }
    }

    static void handleAuthorizationResult(AuthorizationListener listener, AuthorizationResult result) {
        String serverAuthCode = result.getServerAuthCode();
        if (serverAuthCode != null) {
            listener.OnSuccess(serverAuthCode);
        } else listener.OnFail(EMPTY_SERVER_AUTH_CODE);
    }

    static void onException(AuthorizationListener listener, Exception e) {
        listener.OnException(e.toString());
    }
}
public class IntentRunnerActivity extends AppCompatActivity {
    static final AtomicReference<IntentRunnerInitializationListener> listener = new AtomicReference<>(null);
    static final AtomicReference<OnAuthorizationIntentResult> onResult = new AtomicReference<>(null);
    static IntentRunnerActivity instance;
    ActivityResultRegistry registry;
    ActivityResultLauncher<IntentSenderRequest> launcher;

    public static boolean isInitialized() {
        return listener.get() != null;
    }

    public static void initialize(IntentRunnerInitializationListener initializationListener) {
        listener.set(initializationListener);
        Context context = UnityContext.get();
        Intent intent = new Intent(context, IntentRunnerActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.registry = getActivityResultRegistry();
        this.launcher = registry.register(generateKey(), this,
            new ActivityResultContracts.StartIntentSenderForResult(), result -> {
                Intent intent = new Intent(this, UnityActivity.get().getClass());
                intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
                startActivity(intent);
                onResult.get().OnResult(result);
            });
        instance = this;
        listener.get().OnCompleted();
    }

    public static void run(PendingIntent pendingIntent, OnAuthorizationIntentResult onResult) {
        IntentRunnerActivity.onResult.set(onResult);
        instance.launcher.launch(new IntentSenderRequest.Builder(pendingIntent).build());
    }

    private static String generateKey() {
        return UUID.randomUUID().toString();
    }

    public interface OnAuthorizationIntentResult {
        void OnResult(ActivityResult result);
    }
}
public class UnityActivity {
    static UnityActivity instance;
    static final Class<?> unityPlayerClass;
    final Field field;

    static {
        try {
            unityPlayerClass = Class.forName("com.unity3d.player.UnityPlayer");
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    public UnityActivity() throws NoSuchFieldException {
        this.field = unityPlayerClass.getDeclaredField("currentActivity");
        this.field.setAccessible(true);
    }

    static UnityActivity getInstance() throws NoSuchFieldException, ClassNotFoundException {
        if (instance != null) return instance;
        instance = new UnityActivity();
        return instance;
    }

    Activity getActivity() throws IllegalAccessException {
        return (Activity) field.get(null);
    }

    @NonNull
    public static Activity get() {
        try {
            return getInstance().getActivity();
        } catch (IllegalAccessException | NoSuchFieldException | ClassNotFoundException e) {
            //noinspection DataFlowIssue
            return null;
        }
    }
}
public class UnityContext {
    private static final Context applicationContext = UnityActivity.get().getApplicationContext();

    public static Context get() {
        return applicationContext;
    }
}
    implementation 'com.google.android.gms:play-services-auth:21.2.0'
    implementation "androidx.credentials:credentials: 1.3.0-beta02"
    implementation "androidx.credentials:credentials-play-services-auth:1.3.0-beta02"
    implementation "com.google.android.libraries.identity.googleid:googleid:1.1.1"

    def appcompat_version = "1.6.1"
    implementation "androidx.appcompat:appcompat:$appcompat_version"
    implementation "androidx.appcompat:appcompat-resources:$appcompat_version"

Как я могу предотвратить появление всплывающего окна после второго раза?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
63
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Решено.

new AuthorizationRequest.Builder()
    .requestOfflineAccess(clientId, refreshToken) // here

Я обнаружил, что экран согласия отображается каждый раз, когда «истина» передается «forceCodeForRefreshToken» в качестве аргумента функции requestOfflineAccess.

https://developers.google.com/android/reference/com/google/android/gms/auth/api/identity/AuthorizationRequest.Builder

Согласно приведенному выше объяснению

forceCodeForRefreshToken:
If true, the granted code can be exchanged for an access token and a refresh token. 
The first time you retrieve a code, a refresh token will be granted automatically. 
Subsequent requests will require additional user consent. 
Use false by default; 
only use true if your server has suffered some failure and lost the user's refresh token.

Другие вопросы по теме