【问题标题】:Removing account from AccountManager doesn't send user to AccountAuthenticatorActivity从 AccountManager 中删除帐户不会将用户发送到 AccountAuthenticatorActivity
【发布时间】:2015-12-30 13:34:25
【问题描述】:

我有一个使用 AccountManager 和自定义 AccountAuthenticator 注册用户的应用。

我需要实现Log Out 功能。

当用户单击Log Out 按钮时,他们的帐户被成功删除,但活动保持不变,用户不会被重定向到AccountAuthenticatorActivity,尽管如果我关闭应用程序并再次打开它,它将显示身份验证屏幕(即实际删除的帐户)。

我的问题:

我是否必须自己执行重定向(使用finish(); startActivity(...);)或Authenticator 和AccountManager 应该为我处理它(因为我认为如果它被声明为服务,它应该)?


也许我必须实现某种帐户删除侦听器?

无论如何,这就是我删除MainActivity中帐户的方法:

    private void performLogout() {
        Account[] accounts = accountManager.getAccountsByType(AccountGeneral.ACCOUNT_TYPE);
        if (accounts.length != 0) {    
            accountManager.clearPassword(accounts[0]);
            accountManager.invalidateAuthToken(AccountGeneral.ACCOUNT_TYPE,
                    accountManager.getAuthToken(accounts[0], AccountGeneral.AUTHTOKEN_TYPE_FULL_ACCESS, null, true,
                            accountManagerFuture -> {
                                try {
                                    Log.d("invalidateAuthToken", accountManagerFuture.getResult().toString());
                                } catch (android.accounts.OperationCanceledException | AuthenticatorException | IOException e) {
                                    e.printStackTrace();
                                }
                            }, null).toString());

            if (Build.VERSION.SDK_INT < 23) { // use deprecated method
              accountManager.removeAccount(accounts[0], accountManagerFuture -> {
                  try {
                      if (accountManagerFuture.getResult()) {
                          Log.d("Deprecated ACCOUNT REMOVAL", "ACCOUNT  REMOVED");

                      }
                  } catch (android.accounts.OperationCanceledException | IOException | AuthenticatorException e) {
                      e.printStackTrace();
                  }
              }, null);
          } else {
              accountManager.removeAccount(accounts[0], this, accountManagerFuture -> {
                  try {
                      if (accountManagerFuture.getResult() != null) {
                          Log.d("ACCOUNT REMOVAL", "ACCOUNT REMOVED");
                      }
                  } catch (android.accounts.OperationCanceledException | AuthenticatorException | IOException e) {
                      e.printStackTrace();
                  }
              }, null);
          }
        }
    }

顺便说一句,当我点击Log Out 时,我可以在日志中看到以下行:

D/invalidateAuthToken: Bundle[{intent=Intent { cat=[2] cmp=discounty.com/.activities.LoginActivity(有附加功能)}}]

看来我的LoginActivity (AccountAuthenticatorActivity) 确实想要出现,但有些东西阻止了它这样做。

在我的自定义 AccountAuthenticator 中,我实现了这个方法(以及其他几个负责帐户和令牌创建的方法):

@Override
public Bundle getAccountRemovalAllowed(AccountAuthenticatorResponse response, Account account) throws NetworkErrorException {
    Bundle bundle = new Bundle();
    boolean allowed = true;
    bundle.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, allowed);
    return bundle;
}

在我的清单中,我以以下方式声明了服务:

<service
    android:name=".authenticator.DiscountyAuthenticationService"
    android:process=":auth">
    <intent-filter>
        <action android:name="android.accounts.AccountAuthenticator" />
    </intent-filter>
    <meta-data android:name="android.accounts.AccountAuthenticator"
        android:resource="@xml/authenticator" />
</service>

那么,我是否必须手动重定向用户,或者我需要改进代码中的某些内容以使 AccountManager 为我处理重定向?

【问题讨论】:

    标签: android authentication android-service accountmanager android-authenticator


    【解决方案1】:

    当您删除帐户时,AccountManager 不会启动另一个帐户设置。如果你想要这种行为,你需要自己实现它。

    但是,我不建议以这种方式实现它。如果您点击“退出”,您不会期望再次直接重定向到登录屏幕。

    相反,我会显示一条成功消息,例如“已成功注销”,其中包含两个按钮,一个显示“关闭”并关闭应用程序,另一个显示“再次登录”之类的内容,将用户带到登录屏幕再次。恕我直言,这对用户更友好。

    无论如何,回答您的问题:如果您想自动进入登录屏幕,我会看到以下选项:

    1. 只需在用户点击“注销”时启动帐户设置(使用AccountManager.addAccount(...))(可选择使用AccountManager.removeAccountExplicitly(...) 删除帐户)。删除(您自己的应用程序的)帐户不太可能失败(特别是如果您允许在getAccountRemovalAllowed(...) 中返回true),因此在大多数情况下,假设删除成功应该是安全的。您的身份验证器必须处理帐户已经存在的情况,因为用户可以随时启动帐户设置。

    2. 等待accountManagerFuture.getResult() 并开始帐户设置,就像#1 一样,只有当它返回成功时。

    3. 在您的活动中使用addOnAccountsUpdatedListener(...) 注册OnAccountsUpdateListener,以检查帐户是否存在。请注意,有三个触发器会导致调用此侦听器:

      一个。已创建帐户,包括其他应用的帐户

      b.帐户已被删除,包括其他应用的帐户

      c。帐户密码已更新,还包括其他应用程序的帐户(恕我直言,此事件应该对身份验证者保密,绝对不应广播)。

      但是,回调不会收到触发器是什么的任何信息。因此,您需要自行查明您的帐户是否已被删除。

    另请注意,您的代码似乎在主线程中调用accountManagerFuture.getResult(),这不是一个好主意,因为它可能会阻塞。 AccountManager.removeAccount(...) 的文档明确表示这是不允许的。即使您在AccountManagerCallback 回调中调用它,并且您可能认为调用它是安全的,我也不会依赖它并确保它在后台线程中执行。如果您不让用户确认删除,您可能应该致电 AccountManager.removeAccountExplicitly(...)

    【讨论】:

    • 感谢您的详细解答。如果我需要使用 API 级别 21,您是否知道 removeAccountExcplicitly 的最佳等效项是什么?
    • 我们使用AccountManager.removeAccount(account, null, null);。如果getAccountRemovalAllowed返回true,那基本上是一样的操作。在低于 22 的 API 级别上,似乎没有办法绕过对 getAccountRemovalAllowed 的调用,这基本上是 removeAccountExplicitly 所做的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-26
    • 2023-01-31
    • 2012-03-02
    • 1970-01-01
    • 2015-03-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多