我使用GoogleAPIClient
来处理OAuth令牌而不是AccountPicker
。在LoginActivity中它优雅地处理Oauth流,我可以通过轻松调用getAuthToken来获取令牌。但是像所有Oauth令牌一样,此令牌可能会过期,我需要在没有用户干预的情况下进行续订,因为在登录用户已经为应用程序授予了同意权。我正在使用OkHttp Authenticator
来更新令牌,但是问题是GoogleApiClient需要Activity来处理oAuth流,但是我需要在不打扰令牌的情况下续订令牌。
我看过的其他方法是AccountPicker
,无需用户干预即可处理。 Tutorial Link
那么什么应该是正确的方法?
首次登录时使用GoogleApiClient并在SharedPreferences中存储电子邮件地址以及刷新令牌,使用AccountPicker在后台重新进行身份验证?
FWIW,这是我的LoginActivity
package in.jatindhankhar.shorl.ui;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.StringDef;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.widget.Toast;
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.SignInButton;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.Scope;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import in.jatindhankhar.shorl.R;
import in.jatindhankhar.shorl.model.AsyncResponse;
import in.jatindhankhar.shorl.network.GetToken;
import in.jatindhankhar.shorl.utils.Constants;
import in.jatindhankhar.shorl.utils.Utils;
public class LoginActivity extends AppCompatActivity implements GoogleApiClient.OnConnectionFailedListener, AsyncResponse {
private static final String TAG = LoginActivity.class.getSimpleName();
private static final int ACCOUNT_CODE = 1601;
final private Scope URL_SCOPE = new Scope(Constants.URL_API);
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.sign_in_button)
SignInButton signInButton;
private GoogleApiClient mGoogleApiClient;
private Context mContext;
private AccountManager mAccountManager;
private String mAuthTokenType;
public String mAccountName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
ButterKnife.bind(this);
setSupportActionBar(toolbar);
mContext = getApplicationContext();
// Configure sign-in to request the user's ID, email address, and basic
// profile. ID and basic profile are included in DEFAULT_SIGN_IN.
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail().requestScopes(URL_SCOPE).requestId().requestId()
.build();
// Build a GoogleApiClient with access to the Google Sign-In API and the
// options specified by gso.
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this /* Activity */, this /* OnConnectionFailedListener */)
.addApi(Auth.GOOGLE_SIGN_IN_API, gso)
.build();
// Prepare the account manager
mAccountManager = AccountManager.get(mContext);
String accountName = getIntent().getStringExtra(Constants.ARG_ACCOUNT_NAME);
mAuthTokenType = getIntent().getStringExtra(Constants.ARG_AUTH_TYPE);
chooseAccount();
if (mAuthTokenType == null)
mAuthTokenType ="Full access";
signInButton.setSize(SignInButton.SIZE_WIDE);
}
@Override
protected void onResume() {
super.onResume();
mContext = getApplicationContext();
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
}
@OnClick(R.id.sign_in_button)
public void signIn() {
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, Constants.RC_SIGN_IN);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
if (requestCode == Constants.RC_SIGN_IN) {
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
handleSignInResult(result);
}
}
private void handleSignInResult(GoogleSignInResult result) {
Log.d(TAG, "handleSignInResult:" + result.isSuccess());
if (result.isSuccess()) {
// Signed in successfully, show authenticated UI.
GoogleSignInAccount acct = result.getSignInAccount();
if (acct != null) {
mAccountName = acct.getDisplayName();
}
new GetToken(this,acct.getAccount(),Constants.URL_SHORTNER_SCOPE,this).execute();
} else {
// Signed out, show unauthenticated UI.
//updateUI(false);
}
}
private void updateUI(boolean loginSuccess) {
if(loginSuccess)
{
Utils.setLoginSession(mContext,mAccountName);
startActivity(new Intent(mContext,MainActivity.class));
}
else
{
Utils.clearLoginSuccess(mContext);
}
}
@Override
public void processFinish(String output) {
final Account account = new Account(mAccountName, Constants.PACKAGE_NAME);
if (getIntent().getBooleanExtra(Constants.ARG_IS_ADDING_NEW_ACCOUNT, false)) {
String authtokenType = mAuthTokenType;
mAccountManager.addAccountExplicitly(account, "", null);
mAccountManager.setAuthToken(account, authtokenType, output);
} else {
// Just reset the token
mAccountManager.setAuthToken(account,mAuthTokenType,output);
}
Utils.setLoginSession(mContext,mAccountName);
startActivity(new Intent(this,MainActivity.class));
}
private void chooseAccount() {
// use https://github.com/frakbot/Android-AccountChooser for
// compatibility with older devices
Intent intent = AccountManager.newChooseAccountIntent(null, null,
new String[] { "com.google" }, false, null, null, null, null);
startActivityForResult(intent, ACCOUNT_CODE);
}
}
这是我的GetToken asynctask
package in.jatindhankhar.shorl.network;
import android.accounts.Account;
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import com.google.android.gms.auth.GoogleAuthException;
import com.google.android.gms.auth.GoogleAuthUtil;
import com.google.android.gms.auth.UserRecoverableAuthException;
import java.io.IOException;
import in.jatindhankhar.shorl.model.AsyncResponse;
/**
* Created by jatin on 12/12/16.
*/
public class GetToken extends AsyncTask<Void,Void,String> {
private static final String TAG = GetToken.class.getSimpleName();
private Context mAppContext;
private Account mAccountName;
private String AUTH_TOKEN_TYPE;
public AsyncResponse delegate = null;
public GetToken(Context mAppContext,Account mAccountName,String AUTH_TOKEN_TYPE,AsyncResponse delegate)
{
this.mAppContext = mAppContext;
this.mAccountName = mAccountName;
this.AUTH_TOKEN_TYPE = AUTH_TOKEN_TYPE;
this.delegate = delegate;
}
@Override
protected String doInBackground(Void... params) {
try {
if(isCancelled())
{
Log.d(TAG,"doInBackground: task cancelled, so giving up on auth.");
return null;
}
final String token = GoogleAuthUtil.getToken(mAppContext, mAccountName, AUTH_TOKEN_TYPE);
Log.d(TAG,"So token is " + token);
return token;
} catch (UserRecoverableAuthException e) {
e.printStackTrace();
} catch (GoogleAuthException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(String s) {
//super.onPostExecute(s);
delegate.processFinish(s);
}
}