QuinnChen
QuinnChen

Reputation: 730

Fail to get existing token using AccountManager in Interceptor of Retrofit 2.0

一、

When my App launches the MainActivity comes to us, there are not any tokens at this moment so it fails to find token in AccountManager so it goes into LoginActivity.

二、

We input account and password the get token from remote server and save it in local AccountManager。then return to MainActivity.

三、

When come back MainActivity again. I fail to get the local token even it actually exists now. So the app will go into LoginActivity again. If I exit the app and launch it again at this moment, the Mainactivity is able to get the existing token now.

Code

I add token into header in Interceptor of Retrofit 2.0 in this way:

private volatile static Retrofit jsonInstance;

// Returns singleton class instance
public static Retrofit getJsonInstance(final Context context) {
    if (jsonInstance == null) {
        synchronized (Retrofit.class) {
            if (jsonInstance == null) {
                OkHttpClient client = new OkHttpClient();
                client.interceptors().add(new Interceptor() {
                    @Override
                    public com.squareup.okhttp.Response intercept(Chain chain) throws IOException {
                        Request request = chain.request();
                        GitHubAccount gitHubAccount = GitHubAccount.getInstance(context);

                        //Get token here
                        token = gitHubAccount.getAuthToken();

                        request = request.newBuilder()
                                .removeHeader("User-Agent")
                                .addHeader("Authorization", "Token " + token)
                                .addHeader("User-Agent", "Leaking/1.0")
                                //.addHeader("Accept", "application/vnd.github.beta+json")
                                .addHeader("Accept", "application/vnd.github.v3.raw")
                                        .build();
                        return chain.proceed(request);
                    }
                });


                Gson gson = new Gson();
                GsonBuilder builder = new GsonBuilder();
                builder.registerTypeAdapter(Event.class, new EventFormatter());
                gson = builder.create();
                jsonInstance = new Retrofit.Builder()
                        .baseUrl(Constants.BASE_URL)
                        .addConverterFactory(GsonConverterFactory.create(gson))
                        .client(client)
                        .build();

            }
        }
    }
    return jsonInstance;
}

the getAuthToken() method

public String getAuthToken() {

    final AccountManagerFuture<Bundle> future = manager.getAuthToken(account, ACCOUNT_TYPE, null, (BaseActivity)context, null, null);

    try {
        Bundle result = future.getResult();
        return result.getString(AccountManager.KEY_AUTHTOKEN);

    } catch (AccountsException e) {
        Log.e(TAG, "Auth token lookup failed", e);
        return null;
    } catch (IOException e) {
        Log.e(TAG, "Auth token lookup failed", e);
        return null;
    }
}

and then the procedure of manager.getAuthToken will happens in the my custom AccountAuthenticator

 @Override
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
    final AccountManager am = AccountManager.get(context);
    String authToken = am.peekAuthToken(account, authTokenType);
    if (TextUtils.isEmpty(authToken)) {
        final String password = am.getPassword(account);
        if (password != null) {
            Github github = new GithubImpl(context);
            try {
                //Get token from server
                authToken = github.createToken(account.name,password);
            } catch (GithubError githubError) {
                githubError.printStackTrace();
                authToken = "";
            } catch (AuthError authError) {
                authError.printStackTrace();
                authToken = "";
            } catch (OverAuthError overAuthError) {
                overAuthError.printStackTrace();
                authToken = "";
            }
        }else {
            Log.i(TAG, "Try to get AuthToken password is empty");
        }
    }

    if (!TextUtils.isEmpty(authToken)) {

        final Bundle result = new Bundle();
        result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
        result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
        result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
        return result;
    }
    // If we get here, then we couldn't access the user's password - so we
    // need to re-prompt them for their credentials. We do that by creating
    // an intent to display our AuthenticatorActivity.

    final Intent intent = new Intent(context, LoginActivity.class);
    intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
    intent.putExtra(ARG_ACCOUNT_TYPE, account.type);
    intent.putExtra(ARG_AUTH_TYPE, authTokenType);
    final Bundle bundle = new Bundle();
    bundle.putParcelable(AccountManager.KEY_INTENT, intent);

    return bundle;
}

Project

The total project is here https://github.com/Leaking/WeGit

Upvotes: 0

Views: 803

Answers (1)

Nescafemix
Nescafemix

Reputation: 21

Maybe the problem is that you are saving the token in a async process and the saving method is slower than the Get method.

Upvotes: 0

Related Questions