android - 如何在一键登录中使用 Google Activity Result API

标签 android google-api android-signing google-one-tap

在我的一个 Android 应用程序中,我试图按照示例 https://developers.google.com/identity/one-tap/android/get-saved-credentials#disable-one-tap 来包含一键登录身份验证。 .然而,这里https://developer.android.com/reference/androidx/activity/ComponentActivity#startActivityForResult(android.content.Intent,int)它说函数 startActivityForResult 已被弃用,而是使用函数 registerForActivityResult 传递 ActivityResultContract 的 StartActivityForResult 对象。借助其他示例,我可以编写以下代码

 public class MainActivity extends AppCompatActivity {


    private SignInClient oneTapClient;
    private BeginSignInRequest signInRequest;

    private ActivityResultLauncher<Intent> loginResultHandler = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
        // handle intent result here
        if (result.getResultCode() == RESULT_OK) {
            SignInCredential credential = null;
            try {
                credential = oneTapClient.getSignInCredentialFromIntent(result.getData());
                String idToken = credential.getGoogleIdToken();
                String username = credential.getId();
                String password = credential.getPassword();
                if (idToken != null) {
                    // Got an ID token from Google. Use it to authenticate
                    // with your backend.
                    Log.d(TAG, "Got ID token.");
                } else if (password != null) {
                    // Got a saved username and password. Use them to authenticate
                    // with your backend.
                    Log.d(TAG, "Got password.");
                }
            } catch (ApiException e) {
                e.printStackTrace();
            }
        }
        else {
            //...
        }
    });

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //...

        oneTapClient.beginSignIn(signInRequest)
                .addOnSuccessListener(this, new OnSuccessListener<BeginSignInResult>() {
                    @Override
                    public void onSuccess(BeginSignInResult result) {
                       /*try {
                           android.app.Activity.startIntentSenderForResult(result.getPendingIntent().getIntentSender(), REQ_ONE_TAP,
                                    null, 0, 0, 0);
                        } catch (IntentSender.SendIntentException e) {
                            Log.e(TAG, "Couldn't start One Tap UI: " + e.getLocalizedMessage());
                        }*/
                        loginResultHandler.launch(result.getPendingIntent().getIntentSender());
                    }
                })
                .addOnFailureListener(this, new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        // No saved credentials found. Launch the One Tap sign-up flow, or
                        // do nothing and continue presenting the signed-out UI.
                        Log.d(TAG, e.getLocalizedMessage());
                    }
                });
    }
}

只有我不知道如何根据 Google Activity Result API(getIntentSender() 返回一个 IntentSender 但 loginResultHandler.launch() 需要一个 Intent )。任何人都可以帮助我或将我的工作示例链接起来吗?谢谢。

编辑: 最后,我按照以下方式重写了代码(我已经测试到帐户选择屏幕并且可以运行):

public class MainActivity extends AppCompatActivity {

   private static final String TAG = "MainActivity";
    private SignInClient oneTapClient;
    private BeginSignInRequest signInRequest;
    private boolean showOneTapUI = true;

    private ActivityResultLauncher<IntentSenderRequest> loginResultHandler = registerForActivityResult(new ActivityResultContracts.StartIntentSenderForResult(), result -> {
        // handle intent result here
        if (result.getResultCode() == RESULT_OK) Log.d(TAG, "RESULT_OK.");
        if (result.getResultCode() == RESULT_CANCELED) Log.d(TAG, "RESULT_CANCELED.");
        if (result.getResultCode() == RESULT_FIRST_USER) Log.d(TAG, "RESULT_FIRST_USER.");
            try {
                SignInCredential credential = oneTapClient.getSignInCredentialFromIntent(result.getData());
                String idToken = credential.getGoogleIdToken();
                String username = credential.getId();
                String password = credential.getPassword();
                if (idToken !=  null) {
                    // Got an ID token from Google. Use it to authenticate
                    // with your backend.
                    Log.d(TAG, "Got ID token.");
                } else if (password != null) {
                    // Got a saved username and password. Use them to authenticate
                    // with your backend.
                    Log.d(TAG, "Got password.");
                }
            } catch (ApiException e) {
                switch (e.getStatusCode()) {
                    case CommonStatusCodes.CANCELED:
                        Log.d(TAG, "One-tap dialog was closed.");
                        // Don't re-prompt the user.
                        showOneTapUI = false;
                        break;
                    case CommonStatusCodes.NETWORK_ERROR:
                        Log.d(TAG, "One-tap encountered a network error.");
                        // Try again or just ignore.
                        break;
                    default:
                        Log.d(TAG, "Couldn't get credential from result."
                                + e.getLocalizedMessage());
                        break;
                }
            }
    });

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //...

        oneTapClient.beginSignIn(signInRequest)
                .addOnSuccessListener(this, new OnSuccessListener<BeginSignInResult>() {
                    @Override
                    public void onSuccess(BeginSignInResult result) {
                        try {
                            loginResultHandler.launch(new IntentSenderRequest.Builder(result.getPendingIntent().getIntentSender()).build());
                        } catch(android.content.ActivityNotFoundException e){
                            e.printStackTrace();
                            Log.e(TAG, "Couldn't start One Tap UI: " + e.getLocalizedMessage());
                        }
                    }
                })
                .addOnFailureListener(this, new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        // No saved credentials found. Launch the One Tap sign-up flow, or
                        // do nothing and continue presenting the signed-out UI.
                        Log.d(TAG, e.getLocalizedMessage());
                    }
                });
    }
}

最佳答案

您可以使用 ActivityResultContracts.StartIntentSenderForResult类而不是 ActivityResultContracts.StartActivityForResult

因此您可以将您的代码重构为这样的东西,

首先使用 ActivityResultLauncher<IntentSenderRequest> 定义将结果提供给您时将执行的操作实例而不是 ActivityResultLauncher<Intent>实例

private ActivityResultLauncher<IntentSenderRequest> loginResultHandler = registerForActivityResult(new ActivityResultContracts.StartIntentSenderForResult(), result -> {
        // handle intent result here
        if (result.getResultCode() == RESULT_OK) {
            SignInCredential credential = null;
            try {
                credential = oneTapClient.getSignInCredentialFromIntent(result.getData());
                String idToken = credential.getGoogleIdToken();
                String username = credential.getId();
                String password = credential.getPassword();
                if (idToken != null) {
                    // Got an ID token from Google. Use it to authenticate
                    // with your backend.
                    Log.d(TAG, "Got ID token.");
                } else if (password != null) {
                    // Got a saved username and password. Use them to authenticate
                    // with your backend.
                    Log.d(TAG, "Got password.");
                }
            } catch (ApiException e) {
                e.printStackTrace();
            }
        }
        else {
            //...
        }
    });

现在在您的 onCreate 中正如您在上面的代码中提到的,您可以使用 IntentSenderRequest.Builder类转你的IntentSender实例化为 IntentSenderRequest将在 launch 中接受的实例方法

oneTapClient.beginSignIn(signInRequest)
                .addOnSuccessListener(this, new OnSuccessListener<BeginSignInResult>() {
                    @Override
                    public void onSuccess(BeginSignInResult result) {
                     

                        try{
                            loginResultHandler.launch(new IntentSenderRequest.Builder(result.getPendingIntent().getIntentSender()).build());
                           }catch(IntentSenderException e){
                              e.printStackTrace()
                            }
                        
                    }
                })
                .addOnFailureListener(this, new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        // No saved credentials found. Launch the One Tap sign-up flow, or
                        // do nothing and continue presenting the signed-out UI.
                        Log.d(TAG, e.getLocalizedMessage());
                    }
                });
    }

确保将其包装在 try-catch 中构造,它应该是它。

刚刚发现这个answer在谷歌搜索时,它也可能对您有帮助

关于android - 如何在一键登录中使用 Google Activity Result API,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69212531/

相关文章:

java - AES加密j2me

java - Android - 根据按下的按钮添加到 ListView

c# - 下载所有 Google 表格

jquery - Google map 未完全加载

android - 使用 Google Play 上传 key 签署 APK

android - 在webview中单击按钮后,如何在android应用程序中从webview打开外部应用程序?

ruby-on-rails - 尝试使用 Google Calendar API 时出现 "Missing authorization code"错误

android - key 轮换后,我是否仍然需要旧 key 来签署应用程序的更新?

android - 为什么发布版本变体总是可调试的?

android - 崩溃后的 react native 应用程序显示闪屏