我如何强制 GoogleApiClient 在每次调用连接时提示帐户选择器 UI?

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

每当我 运行 在我的第一个应用程序启动周期中 第一次编写代码时

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();

我可以看到以下帐户选择器。

但是,如果之前的连接成功,并且我 运行 在我的第二个应用程序启动周期第一次再次使用相同的代码

帐户选择器不会再次弹出。 GoogleApiClient 将使用帐户名称,我在上一个应用程序启动周期中选择。

我希望每次都能弹出我的帐户选择器。

我遇到了

建议的解决方案不适用于我的情况。

mGoogleApiClient.clearDefaultAccountAndReconnect()

如果我在之前的应用周期中连接过,并且在当前应用周期中第一次调用上述代码,我将得到以下异常。

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)

下面的代码也不行。

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();
}

我可以知道吗,我如何强制 GoogleApiClient 在我每次调用连接时提示帐户选择器 UI?

我每次调用 connect 时 强制 GoogleApiClient 提示帐户选择器 UI 的方法非常老套。如果您有更好的方法,请告诉我们。

它是围绕这个想法构建的。

  1. 如果显示帐户选择器 UI,onConnectionFailed 必须至少触发一次。
  2. onConnected中,我们可以检查onConnectionFailed是否至少被触发过一次。如果没有,我们将调用 clearDefaultAccountAndReconnect.

这是这个想法的完整代码。

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;
}

GDAA and the REST Api 中,您有两个选择:
1/ 你不指定账号,由底层系统管理。
2/ 您自己管理帐户。

如果您使用第一种方法,您永远不会知道您的应用程序的用户是谁 selected。您只能通过 clearDefaultAccountAndReconnect 来 'clean' 帐户。 selection 对话框再次弹出,用户可以 select(添加)另一个帐户。

如果您需要了解当前 selected 用户帐户(即用于缓存/持久性),您必须select自行管理帐户,如您所见here (for REST) or here (for GDAA) -只需沿着 REQ_ACCPICK 路径和 UT.AM class 路径即可。这样你就可以完全控制了。

所以,对你的问题的简短回答是你弹出

startActivityForResult(AccountPicker.newChooseAccountIntent(null,
        null, new String[]{GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE}, true, null, null, null, null),
        REQ_ACCPICK);

activity 自己并交付结果

email = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME)

您的 setAccountName(email) 如:

   GAC = new GoogleApiClient.Builder(act)
      .addApi(Drive.API)
      .addScope(Drive.SCOPE_FILE)
      .addScope(Drive.SCOPE_APPFOLDER)
      .addConnectionCallbacks(...)
      .addOnConnectionFailedListener(...)
      ....
      .setAccountName(email)
      ....
      .build();

祝你好运

我发现重新创建 API 客户端更容易,如果它没有连接或连接,然后它会再次提示输入帐户。

目前看来您无法清除默认帐户,除非已连接 GoogleApiClient。我们可以通过引入一个布尔标志来解决这个问题,告诉我们是否需要清除默认帐户。

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...
}

在调用 mGoogleApiClient.connect() 之前,适当地设置布尔状态标志以提示输入帐户以根据需要使用当前默认帐户。 请注意,如果用户在设备上只有一个帐户,您可能会产生多余的 connect() 调用。

protected void connectToGoogleApi(final boolean clearDefaultAccount) {
    if (clearDefaultAccount && mGoogleApiClient.isConnected()) {
        mClearDefaultAccount = false;
        mGoogleApiClient.clearDefaultAccountAndReconnect();
    } else {
        mGoogleApiClient.connect();
    }
}

我想我迟到了,但我就是这样解决的。

在我启动 Google SignIn Intent 之前,它将显示生成器。 Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient); startActivityForResult(signInIntent, RC_SIGN_IN);

这样做:

if (mGoogleApiClient.hasConnectedApi(Auth.GOOGLE_SIGN_IN_API)) { mGoogleApiClient.clearDefaultAccountAndReconnect(); }

因为 mGoogleApiClient 由于某种原因存储登录用户。因此,如果您执行 mGoogleApiClient.isConnected(),它可能不会始终有效,即使您正在重新创建 mGoogleApiClient 的实例。但是,这将强制它清除已选择的用户。

已测试,有效。

接受的解决方案确实有效(尽管如果您想导入 API 的更新版本,您还必须包含 google-play-services-auth api到您的应用程序中),但帐户选择器将以不同的样式显示,这可能会使用户感到困惑或担心。

如果您想保持 UI 统一并且不想包含 google-play-services-auth API.

,我提供了 2 个替代解决方案,它们很有吸引力

您可以调用 mGoogleApiClient.clearDefaultAccountAndReconnect(),然后在您想要强制用户选择帐户时调用 mGoogleApiClient.disconnect() 立即断开连接。通过这样做,您可以在下次用户必须连接时调用 mGoogleApiClient.connect() 来连接(强制帐户选择器)。这在您想要触发用户再次选择帐户的特定事件时很有用。

另一个(更普遍有用的)解决方案以相同的方式执行以下操作(在后台线程中,可能 AsyncTask)而不是最终代码块:

mGoogleApiClient.blockingConnect();
if (mGoogleApiClient.isConnected()) {
    mGoogleApiClient.clearDefaultAccountAndReconnect();
}

这将避免您看到的空指针异常,并将明确强制帐户选择器。这有点奇怪,因为你连接了两次,但它有效。

如果 Google 在 GoogleApiClient 中明确提供此功能就好了。

通过混合搭配上述解决方案,我得到了它:

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();

希望它能帮助其他人节省一些时间。 =)

问题是你退出了内部activity,而不是从登录一个,但是如果你每次在登录之前退出,那么它就会解决。 简单的! , 只需添加

mGoogleSignInClient.signOut();

在您开始登录之前,即:

Intent signInIntent = mGoogleSignInClient.getSignInIntent(); 

这将在您登录之前注销任何用户。