问题
Whenever I run the code for the very first time at my 1st app launched cycle
GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(context)
.addApi(Drive.API)
.addScope(Drive.SCOPE_APPFOLDER) // required for App Folder sample
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mGoogleApiClient.connect();
I can see the following account chooser.
However, if previous connect is success, and I run the same code again for first time at my 2nd app launched cycle.
The account chooser will not pop up again. GoogleApiClient
is going to use the account name, I choose in previous app launch cycle.
I wish to have my account chooser pop up every-time.
I came across How to Clear GoogleApiClient Default Account and Credentials
The proposed solution doesn't work for my case.
mGoogleApiClient.clearDefaultAccountAndReconnect()
If I had been connected for my previous app cycle, and I call the above code first time in my current app cycle, I will get the following exception.
java.lang.IllegalStateException: GoogleApiClient is not connected yet.
at com.google.android.gms.common.internal.zzx.zza(Unknown Source)
at com.google.android.gms.common.api.internal.zzj.clearDefaultAccountAndReconnect(Unknown Source)
The following code won't work either.
if (mGoogleApiClient.isConnected()) {
// No chance to execute this code, if you run this code during app launch.
mGoogleApiClient.clearDefaultAccountAndReconnect();
} else {
// No account chooser will pop up if you had been connected in previous app life cycle
mGoogleApiClient.connect();
}
May I know, how can I enforce GoogleApiClient to prompt account chooser UI each time I call connect?
回答1:
In both GDAA and the REST Api, you have two options:
1/ you do not specify the account and the underlying system will manage it.
2/ you manage the account yourself.
If you use the first approach, you will never know who the user of your app selected. You can only 'clean' the account by means of clearDefaultAccountAndReconnect
. The selection dialog pops up again and the user can select (add) another account.
If you need to know the current selected user account (i.e. for caching /persistence), you must manage the account selection yourself as you can see here (for REST) or here (for GDAA) - just follow the REQ_ACCPICK
trail and the UT.AM
class. This way you'll be in full control.
So, the short answer to your question is that you pop the
startActivityForResult(AccountPicker.newChooseAccountIntent(null,
null, new String[]{GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE}, true, null, null, null, null),
REQ_ACCPICK);
activity yourself and deliver the resulting
email = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME)
to your setAccountName(email)
as in:
GAC = new GoogleApiClient.Builder(act)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.addScope(Drive.SCOPE_APPFOLDER)
.addConnectionCallbacks(...)
.addOnConnectionFailedListener(...)
....
.setAccountName(email)
....
.build();
Good Luck
回答2:
I think I am late to this but this is how I solved it.
Before I start the Google SignIn Intent which will show the builder.
Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
startActivityForResult(signInIntent, RC_SIGN_IN);
Do this:
if (mGoogleApiClient.hasConnectedApi(Auth.GOOGLE_SIGN_IN_API)) {
mGoogleApiClient.clearDefaultAccountAndReconnect();
}
Since mGoogleApiClient
for some reason stores the logged in user. So if you do mGoogleApiClient.isConnected()
it might not work always, even if you are recreating the instance of mGoogleApiClient
. However, this will force it to clear the already selected user.
Tested and it works.
回答3:
Looks like currently you can not clear the default account unless GoogleApiClient is already connected. We can work around this by introducing a boolean flag to tell us if we need to clear the default account.
private boolean mClearDefaultAccount;
@Override
public void onConnectionFailed(ConnectionResult result) {
if (!mIntentInProgress && result.hasResolution()) {
try {
mIntentInProgress = true;
mClearDefaultAccount = false;
startIntentSenderForResult(result.getResolution().getIntentSender(),
GOOGLE_PLUS, null, 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
mIntentInProgress = false;
// report error
}
} else if (!mIntentInProgress) {
// report error
}
}
@Override
public void onConnected(Bundle bundle) {
if (mClearDefaultAccount) {
mClearDefaultAccount = false;
mGoogleApiClient.clearDefaultAccountAndReconnect();
return;
}
// connected...
}
Before calling mGoogleApiClient.connect()
set the boolean state flag appropriately to prompt for account to use to use the current default account as necessary.
Note that you may incur a redundant connect()
call if user has only one account on the device.
protected void connectToGoogleApi(final boolean clearDefaultAccount) {
if (clearDefaultAccount && mGoogleApiClient.isConnected()) {
mClearDefaultAccount = false;
mGoogleApiClient.clearDefaultAccountAndReconnect();
} else {
mGoogleApiClient.connect();
}
}
回答4:
I found it easier to just recreate the API client if it's not connected or connecting, then it prompts for the account again.
回答5:
With a mix and match of solutions above, i got it working with this:
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this, new GoogleApiClient.OnConnectionFailedListener() {
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
}
})
.addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
@Override
public void onConnected(@Nullable Bundle bundle) {
mGoogleApiClient.clearDefaultAccountAndReconnect(); // To remove to previously selected user's account so that the choose account UI will show
}
@Override
public void onConnectionSuspended(int i) {
}
})
.addApi(Auth.GOOGLE_SIGN_IN_API, new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).requestEmail().build())
.build();
Hope it helps others save some time. =)
回答6:
My method of enforcing GoogleApiClient to prompt account chooser UI each time I call connect is pretty hackish. If you know any better way, please let us know.
It is built around the idea.
- If the account chooser UI is shown,
onConnectionFailed
must be triggered at least once. - In
onConnected
, we can check whetheronConnectionFailed
has been triggered at least once. If not, we will callclearDefaultAccountAndReconnect
.
Here's the complete code for such idea.
public class GoogleApiClientFragment extends Fragment implements
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
public static GoogleApiClientFragment newInstance() {
return new GoogleApiClientFragment();
}
/**
* Handles resolution callbacks.
*/
@Override
public void onActivityResult(int requestCode, int resultCode,
Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RequestCode.REQUEST_GOOGLE_API_CLIENT_CONNECT && resultCode == Activity.RESULT_OK) {
mGoogleApiClient.connect();
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Override
public void onResume() {
super.onResume();
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(this.getContext())
.addApi(Drive.API)
.addScope(Drive.SCOPE_APPFOLDER)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
accountPickerShown = false;
mGoogleApiClient.connect();
}
}
@Override
public void onPause() {
super.onPause();
if (mGoogleApiClient != null) {
mGoogleApiClient.disconnect();
}
}
@Override
public void onConnected(Bundle bundle) {
Log.i(TAG, "GoogleApiClient connected");
if (accountPickerShown == false && mGoogleApiClient.isConnected()) {
mGoogleApiClient.clearDefaultAccountAndReconnect();
}
}
@Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "GoogleApiClient connection suspended");
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.i(TAG, "GoogleApiClient connection failed: " + connectionResult.toString());
if (!connectionResult.hasResolution()) {
// show the localized error dialog.
GoogleApiAvailability.getInstance().getErrorDialog(this.getActivity(), connectionResult.getErrorCode(), 0).show();
return;
}
try {
accountPickerShown = (connectionResult.getErrorCode() == ConnectionResult.SIGN_IN_REQUIRED);
connectionResult.startResolutionForResult(this.getActivity(), RequestCode.REQUEST_GOOGLE_API_CLIENT_CONNECT);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "Exception while starting resolution activity", e);
}
}
private boolean accountPickerShown = false;
private static final String TAG = "GoogleApiClientFragment";
private GoogleApiClient mGoogleApiClient;
}
回答7:
The accepted solution does work (though you will also have to include the google-play-services-auth
api if you would like to import a more up-to-date version of the API into your application), but the account picker will show up in a different style which could confuse or concern users.
I offer 2 alternate solutions that are enticing if you want to keep your UI uniform and do not want to include the google-play-services-auth
API.
You can call mGoogleApiClient.clearDefaultAccountAndReconnect()
then immediately disconnect by calling mGoogleApiClient.disconnect()
whenever you want to force a user to pick an account. By doing this, you can just call mGoogleApiClient.connect()
to connect (forcing the account picker) the next time the user has to connect. This is useful when there is a specific event that you want to trigger the user picking an account again.
Another (more generally useful) solution in this same fashion would be to do the following (in a background thread, probably AsyncTask
) instead of your final code block:
mGoogleApiClient.blockingConnect();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.clearDefaultAccountAndReconnect();
}
This will avoid the null pointer exception you were seeing and will force the account picker explicitly. It is a bit weird since you are connecting twice, but it works.
It would be nice if Google provided this functionality in the GoogleApiClient
explicitly.
来源:https://stackoverflow.com/questions/34701380/how-can-i-enforce-googleapiclient-to-prompt-account-chooser-ui-each-time-i-call