How can I enforce GoogleApiClient to prompt account chooser UI each time I call connect?

独自空忆成欢 提交于 2019-11-26 16:36:44

问题


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.

  1. If the account chooser UI is shown, onConnectionFailed must be triggered at least once.
  2. In onConnected, we can check whether onConnectionFailed has been triggered at least once. If not, we will call clearDefaultAccountAndReconnect.

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!