使用旧密码登录Google帐户 - 如何重定向到蓝色Google登录页面?

dea*_*ish 24 android google-account google-signin google-identity

我已经在我的应用中实施了Google登录SDK,一切正常.

当我点击登录按钮 - 我得到已存储帐户的窗口.我选择其中一个,登录的整个过程以成功结束.

但是有一个用例我无法通过,我不知道如何解决这个问题:

  • 当用户访问Google登录对话框并点击已更改密码的帐户时该怎么办?

我跟着谷歌指令"实施登录SDK"并在调用这些行之后:

Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
GoogleSignInAccount googleSignInAccount = task.getResult(ApiException.class);
Run Code Online (Sandbox Code Playgroud)

我捕获状态代码为12501的异常SIGN_IN_CANCELLED.

正如我之前所说,这是因为其中一个存储的帐户密码无效.

如何让用户重定向到此蓝色Google登录页面并保持当前流量?

例如,AliExpress可以以某种方式处理此问题并将用户重定向到蓝页,并要求用户再次登录.

在此输入图像描述

我的代码与Google的说明没有太大区别.这是我的代码流程.一切都从onClick():

onClick()方法中:

// Logout before all operations
GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this);
if (account != null) {
    mGoogleSignInClient.signOut();
}

// Call to sign in
Intent signInIntent = mGoogleSignInClient.getSignInIntent();
startActivityForResult(signInIntent, RequestCodes.RC_GOOGLE_SIGN_IN);
Run Code Online (Sandbox Code Playgroud)

onActivityResult部分:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    Log.d(TAG, "onActivityResult() called with: requestCode = [" + requestCode + "], resultCode = [" + resultCode + "], data = [" + data + "]");

    if (requestCode == RequestCodes.RC_GOOGLE_SIGN_IN) {

        try {

            // Call to take account data
            Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);

            // Fetch account data
            GoogleSignInAccount googleSignInAccount = task.getResult(ApiException.class);

            Account account = googleSignInAccount.getAccount();

            // Calling to get short lived token
            String shortLivedToken = GoogleAuthUtil.getToken(mContext, account, "oauth2:" + Scopes.PROFILE + " " + Scopes.EMAIL);

            // Further calls here...

        } catch (ApiException e) {

            //https://developers.google.com/android/reference/com/google/android/gms/auth/api/signin/GoogleSignInStatusCodes

            if (e.getStatusCode() == 12501) {
                Log.e(TAG, "SIGN_IN_CANCELLED");
            } else if (e.getStatusCode() == 12502) {
                Log.e(TAG, "SIGN_IN_CURRENTLY_IN_PROGRESS");
            } else if (e.getStatusCode() == 12500) {
                Log.e(TAG, "SIGN_IN_FAILED");
            } else {
                e.printStackTrace();
            }

        } catch (GoogleAuthException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    } else {
        super.onActivityResult(requestCode, resultCode, data);
    }
}
Run Code Online (Sandbox Code Playgroud)

Ama*_*oft 5

免责声明 我不是Google员工。我在下面所说的一切都是我从调查类似问题得出的结论。

简短答案

您所做的一切正确。这是登录Google帐户的推荐方法。不幸的是,此机制中没有实际的回调来指定您所遇到的实际错误。Google Play服务处理此问题的方式是通过通知用户其凭据已被通知废弃,您可以在下面看到该信息(更改密码后即刻)。

通知

建议您在https://issuetracker.google.com上为您的案例添加额外的结果代码,以提交一个错误,因为这似乎是明智的改进。

长答案

Google 就像其他所有人一样使用Android帐户API(您可以自己尝试)。在后台,它只是一个oauth令牌检索和存储机制。

更改密码后,令牌将不再有效,并且在使用该令牌时会出现错误。

它的工作方式是Google Play服务开发人员选择实施的方式(因此,我建议您提交错误)。

例如,速卖通可以以某种方式处理此问题并将用户重定向到蓝页,并要求用户再次登录。

Aliexpress使用已弃用的API。如您所见,用于选择帐户的对话框具有不同的颜色,并且没有头像。该API仍然可用,但可以随时(或不关闭)该API。我不建议您使用它,但是这是它的工作方式:

import com.google.android.gms.common.AccountPicker;
import com.google.android.gms.auth.GoogleAuthUtil;
import com.google.android.gms.auth.UserRecoverableAuthException;

void chooseAccount() {
    Intent signInIntent = AccountPicker.newChooseAccountIntent(null, null, new String[]{GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE}, true, null, null, null, null);
    startActivityForResult(signInIntent, REQ_CHOOSE_ACCOUNT);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

    if (requestCode == REQ_CHOOSE_ACCOUNT) {

        String email = data.getExtras().getString("authAccount");
        // better do this in background thread
        try {
            GoogleAuthUtil.getToken(this, new Account(email, GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE), "oauth2:https://www.googleapis.com/auth/userinfo.profile");
        } catch (UserRecoverableAuthException recEx) {
            Intent recoverIntent = recEx.getIntent();
            // Will redirect to login activity
            startActivityForResult(recoverIntent, REQ_RECOVER);
        } catch (Exception e) {
            Log.d(TAG, "caught exception", e);
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你!

UPD:新的Google Play API具有ResolvableApiException,它扩展了您正在捕获的ApiException。它的方法startResolutionForResult()与旧版API中使用的方法类似。但是您收到的捆绑包不包含解决方案信息。

Bundle[{googleSignInStatus=Status{statusCode=unknown status code: 12501, resolution=null}}]
Run Code Online (Sandbox Code Playgroud)

如果您要提交错误,请在此处发布,我们将对其加注星标)

您还可以使用默认的Android API(最低API 23)显示“选择帐户”对话框

可以使用以下代码使用默认的Android帐户管理API来显示“选择帐户对话框” 。这是新功能,并且(希望)暂时不会弃用。

import android.accounts.Account;
import android.accounts.AccountManager;

// Unfortunately can be used only on API 23 and higher
Intent signInIntent = AccountManager.newChooseAccountIntent(
            null,
            null,
            new String[] { "com.google" },
            "Please select your account",
            null,
            null,
            new Bundle());

startActivityForResult(signInIntent, REQ_SELECT_ACCOUNT);

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQ_SELECT_ACCOUNT) {
            String accountName = data.getExtras().getString(AccountManager.KEY_ACCOUNT_NAME);
            String accountType = data.getExtras().getString(AccountManager.KEY_ACCOUNT_TYPE);
            // now you can call GoogleAuthUtil as in example above
        }
    }
Run Code Online (Sandbox Code Playgroud)

您还可以获取对您的应用可见的Google帐户列表

在用户尝试使用上述方法之一使用该类型帐户登录到您的应用后,该帐户对您的应用变为可见。如果登录失败(例如密码已过期),则会发生此事件您将在列表中看到该帐户(但是,如果有多个帐户,则无法区分哪个帐户)。因此,可以将其用作解决方法,但使用方式有限。

import android.accounts.Account;
import android.accounts.AccountManager;

try {
        // requires android.permission.GET_ACCOUNTS
        Account[] accounts = AccountManager.get(this).getAccountsByType("com.google");
        for (Account account : accounts) {
            Log.d(TAG, "account: " + account.name);
        }
    } catch (Exception e) {
        Log.i("Exception", "Exception:" + e);
    }
Run Code Online (Sandbox Code Playgroud)

结论 不幸的是,我发现没有其他方法可以使用现代的Google登录API访问Google帐户数据来解决您的情况。所有高级AccountManager API均要求您与帐户所有者应用(GMS-Google Mobile Services)具有相同的签名,但情况并非如此。因此,我们只能向Google提出要求,并希望其得以实施:(