アプリケーションにGoogleサインインSDKを実装しましたが、正常に動作します。サインインボタンをクリックすると、既に保存されているアカウントを表示するウィンドウが開きます。これらのアカウントの1つを選択すると、サインインプロセスが正常に終了します。
成功しない1つの使用例は、ユーザーがサインインダイアログにアクセスして、無効なパスワードを持つアカウントをクリックした場合です。この問題の解決方法がわかりません。
私はGoogleの「サインインSDKの実装」の指示に従い、次の行を呼び出した後、
_Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
GoogleSignInAccount googleSignInAccount = task.getResult(ApiException.class);
_
ステータスコード12501 _SIGN_IN_CANCELLED
_で例外をキャッチします。
前に述べたように、これは、保存されたアカウントの1つに無効なパスワードがあるために発生します。
再現する手順は次のとおりです。
ユーザーにこの青い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の従業員ではありません。以下に述べるすべては、同様の問題を調査した結果です。
短い答え
あなたはすべてを正しく行っています。これは、Googleアカウントへのログインに推奨される方法です。残念ながら、このメカニズムには、実際の問題を特定するための実際のコールバックはありません。 Google Play開発者サービスがこれを処理する方法は、以下に表示される通知(パスワードが変更された直後)によって資格情報が古くなったことをユーザーに通知することです。
https://issuetracker.google.com でケースに結果コードを追加するためのバグを報告することをお勧めします。
長い答え
Googleは AndroidアカウントAPI を使用しています(他の人と同じです(自分で試すことができます)。舞台裏では単なるoauthトークンの取得と保存のメカニズムです。
パスワードが変更された場合、トークンは無効になり、使用しようとするとエラーが発生します。
これが機能する方法は、Google Play Services開発者が実装することを選択した方法です(したがって、バグを報告することをお勧めします)。
たとえば、AliExpressはどういうわけかこれを処理でき、ユーザーに再度サインインするように求めて、ユーザーをブルーページにリダイレクトします。
Aliexpressは 非推奨の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を拡張します。以前のAPIで使用されていたのと同様のメソッドstartResolutionForResult()があります。ただし、受け取るバンドルには解決情報が含まれていません。
Bundle[{googleSignInStatus=Status{statusCode=unknown status code: 12501, resolution=null}}]
バグを報告する場合は、ここに投稿してください。スターを付けます)
デフォルトのAndroid API(最小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にのみリクエストでき、実装されることを望みます:(