Вход в систему дважды при использовании SyncAdapters - программирование
Подтвердить что ты не робот

Вход в систему дважды при использовании SyncAdapters

Я создаю новое приложение для Android с помощью SyncAdapter для обработки синхронизации db. У меня все на месте, и приложение работает нормально, но я заметил, что я дважды зашел в систему.

Первый вход в систему происходит, когда класс AuthenticatorActivity (он расширяет AccountAuthenticatorActivity) проверяет пользователя и пароль.

Если пользователь и пароль верны, AuthenticatorActivity выполняет следующее:

  • Если account не существует, он создает его с помощью mAccountManager.addAccountExplicitly()
  • authToken сохраняется с помощью intent.putExtra(AccountManager.KEY_AUTHTOKEN, authToken);

Это было в основном скопировано/вставлено из образцов Android, поэтому я думаю, что все в порядке.

Проблема заключается в том, что когда SyncAdapter запускает и использует

authtoken = mAccountManager.blockingGetAuthToken(account,
          AuthenticatorActivity.PARAM_AUTHTOKEN_TYPE, true);

Вызывается метод getAuthToken() внутри класса Authenticator, который расширяет AbstractAccountAuthenticator. И внутри этого метода я снова попадаю в конечную точку входа.

С этого момента конечная точка входа не попадает снова, пока истечет authToken.

Это не то, что меня очень беспокоит, но я хотел бы знать, есть ли способ избежать повторного входа в систему дважды.

4b9b3361

Ответ 1

Как вы видели, хотя Authenticator.java в SampleSyncAdapter говорит

Интересным, что демонстрирует этот класс, является использование authTokens как части процесса аутентификации.... Если у нас уже есть authToken, хранящийся в учетной записи, мы возвращаем это authToken. Если мы этого не сделаем, но у нас есть имя пользователя и пароль, мы попытаемся поговорить с образцом службы, чтобы получить authToken.

что ложь. Authenticator.getAuthToken не проверяет кеш, он просто попадает в сеть, чтобы получить токен.

Решение состоит в том, чтобы добавить недостающую проверку:

Authenticator.java:
@Override
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account,
        String authTokenType, Bundle loginOptions) throws NetworkErrorException {

    // check that authToken type supported
    ...

    // Check if we already have a cached token to return
    final AccountManager am = AccountManager.get(mContext);
    String cachedAuthToken = am.peekAuthToken(account, authTokenType);
    if (cachedAuthToken != null) {
        final Bundle result = new Bundle();
        result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
        result.putString(AccountManager.KEY_ACCOUNT_TYPE, Constants.ACCOUNT_TYPE);
        result.putString(AccountManager.KEY_AUTHTOKEN, cachedAuthToken);
        return result;
    }

    // Get new authToken from server
    ...

    // If all else fails, prompt the user for credentials
    ...
}

Обратите внимание, что остальная часть вашего проекта должна религиозно использовать AccountManager.invalidateAuthToken, когда вызовы терпят неудачу, иначе вы закончите с бесконечным циклом сбоев вызовов, попыткой получить новый токен аутентификации, а затем снова сработаете, когда тот же кэшированный токен аутентификации.