【问题标题】:How can I enforce GoogleApiClient to prompt account chooser UI each time I call connect?如何在每次调用 connect 时强制 GoogleApiClient 提示帐户选择器 UI?
【发布时间】:2016-04-14 13:44:06
【问题描述】:

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

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 将使用帐户名,我在上一个应用启动周期中选择。

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

我遇到了How to Clear GoogleApiClient Default Account and Credentials

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

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 在每次调用 connect 时提示帐户选择器 UI?

【问题讨论】:

    标签: android google-play-services google-drive-android-api


    【解决方案1】:

    GDAAREST Api 中,您有两种选择:
    1/你不指定账户,底层系统会管理它。
    2/ 您自己管理帐户。

    如果您使用第一种方法,您将永远不会知道您的应用的用户选择了谁。您只能通过clearDefaultAccountAndReconnect 来“清理”帐户。选择对话框再次弹出,用户可以选择(添加)另一个帐户。

    如果您需要知道当前选择的用户帐户(即用于缓存/persistence),您必须自己管理帐户选择,如您所见here (for REST)here (for GDAA) - 只需按照REQ_ACCPICK 跟踪和@ 987654327@上课。这样你就可以完全掌控。

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

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

    自己活动并交付结果

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

    祝你好运

    【讨论】:

    • 我没有意识到我们可以直接setAccountName。谢谢。
    • 但请记住,它必须是来自您的帐户选择器的电子邮件之一(设备上的有效帐户)。并且没有“getAccountName()”,所以你必须自己坚持它们(我上面提到的 UT.AM 类)..
    • @seanpj,答案确实对我有帮助,但不了解 UT.AM 课程。不知道什么不是,以及它的目的。请告诉我。谢谢。
    • 可惜我已经退休半年了,不能太具体(记性不好)。但我记得,AM 类只是用于保存当前帐户信息(应用程序必须记住它并决定是从其持久性存储库中获取帐户还是要求用户选择一个)。我知道,这是一个糟糕的答案,但我可以从环游欧洲的火车上给你最好的答案 :-) 另外我真的不知道自原始答案以来 GDAA 层是如何变化的(始终注意答案的日期) .
    • 另一点:AccountPicker.newChooseAccountIntent() 创建的选择器对话框与 GooglePlayServices 中内置的完全不同。更糟糕的是:主题不正确,浅色主题背景为深色,小部件在黑色背景上为黑色。看起来 google 的那些家伙连最琐碎的测试都不会费心。
    【解决方案2】:

    我想我迟到了,但这就是我解决它的方法。

    在我启动 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 的实例。但是,这将强制它清除已选择的用户。

    经过测试,它可以工作。

    【讨论】:

    • 不工作。 mGoogleApiClient.hasConnectedApi(Auth.GOOGLE_SIGN_IN_API) 总是返回 false
    • @Kamil,非常感谢!)这是可行的解决方案
    【解决方案3】:

    目前您似乎无法清除默认帐户,除非 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();
        }
    }
    

    【讨论】:

      【解决方案4】:

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

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

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

        • 你先生,真是个天才。
        • 我将收回我之前的评论。 GoogleApiClient 以某种方式存储先前选择的用户并将其用于后续连接。您的提议无效。
        【解决方案6】:

        我的每次调用 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;
        }
        

        【讨论】:

          【解决方案7】:

          接受的解决方案确实有效(但如果您想将更新版本的 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 中明确提供此功能,那就太好了。

          【讨论】:

            【解决方案8】:

            问题是您退出了内部活动,而不是从 signIn 之一,但是如果您每次在登录前都退出,那么它会得到解决。 简单的! ,只需添加

            mGoogleSignInClient.signOut();
            

            在您开始登录之前,即:

            Intent signInIntent = mGoogleSignInClient.getSignInIntent(); 
            

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

            【讨论】:

              猜你喜欢
              • 2019-10-28
              • 2016-06-17
              • 2014-12-01
              • 1970-01-01
              • 2013-01-01
              • 1970-01-01
              • 2020-01-20
              • 2017-02-24
              • 2016-12-26
              相关资源
              最近更新 更多