我已将Google登录SDK实施到我的应用程序中,它运行正常。当我点击登录按钮时,会打开一个窗口,显示已存储的帐户。选择其中一个帐户会成功结束登录过程。
未通过的一个用例是当用户进入登录对话框并单击具有无效密码的帐户时。我不知道如何解决这个问题。
我跟着谷歌指令“实施登录SDK”并在调用这些行之后:
Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
GoogleSignInAccount googleSignInAccount = task.getResult(ApiException.class);
我捕获状态代码为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);
在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);
}
}
免责声明我不是谷歌员工。我在下面说的一切都是我调查类似问题的结论。
简短的回答
你正在做的一切正确。这是登录谷歌帐户的推荐方式。不幸的是,在这个机制中没有实际的回调来指定你的案例中实际出错的地方。 Google Play服务处理它的方式是通过下面的通知(密码更改后)通知用户他的凭据已过时。
我建议在https://issuetracker.google.com上为你的案例添加额外的结果代码提交一个错误,因为它似乎是一个明智的改进。
答案很长
Google就像其他人一样使用Android account API(您可以自己尝试)。在幕后它只是一个oauth令牌检索和存储机制。
更改密码后,令牌不再有效,您尝试使用它时会出错。
它的工作方式是Google Play服务开发人员选择实施它的方式(因此我建议您提交错误)。
例如,AliExpress可以以某种方式处理此问题并将用户重定向到蓝页,并要求用户再次登录。
Aliexpress使用deprecated 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);
}
}
}
希望能帮助到你!
UPD:新的Google Play API有ResolvableApiException,它扩展了您正在捕获的ApiException。它的方法startResolutionForResult()类似于旧API中使用的方法。但是您收到的Bundle不包含解决方案信息。
Bundle[{googleSignInStatus=Status{statusCode=unknown status code: 12501, resolution=null}}]
如果您要提交错误,请在此处发布,我们将为其加注星标)
您还可以使用默认的Android API显示“选择帐户”对话框(min API 23)
以下代码可能会被起诉以使用default Android Account Management APIs显示“选择帐户对话框”。这是新的,(希望)暂时不会被弃用。
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
}
}
您还可以获取应用可见的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);
}
结论遗憾的是,我发现没有其他方法可以使用现代Google登录API访问Google帐户数据来处理您的案例。所有高级AccountManager API都要求您拥有与帐户所有者应用(GMS - Google移动服务)相同的签名,但并非如此。所以我们只能从Google请求这个并希望它能够实现:(