首页 > 解决方案 > 如何将 registerForActivityResult 与 StartIntentSenderForResult 合同一起使用?

问题描述

我正在编写一个 Kotlin 应用程序并使用 Firebase 进行身份验证。正如onActivityResult现在已经过时的那样,我正在尝试将我的应用程序迁移到使用registerForActivityResult. 我有一个指向 Google 帐户功能的链接,它以 Google 登录流程开始,如此处所示。我的代码:

    private fun initGoogleSignInClient() =
        activity?.let {

            // Configure Google Sign In
            val gso =
                GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
                    .requestIdToken(getString(R.string.default_web_client_id))
                    .requestEmail()
                    .build()

            // Build a GoogleSignInClient with the options specified by gso.
            viewModel.googleSignInClient = GoogleSignIn.getClient(it, gso)
        }

    private fun showLinkWithGoogle() =
        startActivityForResult(viewModel.googleSignInClient.signInIntent, RC_LINK_GOOGLE)

initGoogleSignInClient在片段中调用where onCreateViewshowLinkWithGoogle当用户点击屏幕上的按钮时调用。这完美地工作。我使用 查找了一个示例,我找到的最好的示例在页面registerForActivityResult的底部。我添加了这段代码:

    private val linkWithGoogle =
        registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) {
            viewModel.handleGoogleResult(it.data)
        }

    private fun showLinkWithGoogle() =
        linkWithGoogle.launch(IntentSenderRequest.Builder(viewModel.googleSignInClient.signInIntent))

但意识到IntentSenderRequest.Builder需要一个IntentSender而不是一个Intent. 我还没有找到任何关于如何IntentSender从. 谁能提供一个完整的使用示例?IntentGoogleSignInClientregisterForActivityResult(ActivityResultContracts.StartIntentSenderForResult())

非常感谢!

标签: kotlinandroid-intentfirebase-authenticationgoogle-signinactivity-result-api

解决方案


对于这个用例,您不需要一个ActivityResultContracts类型StartIntentSenderForResult,而是一个类型StartActivityForResult。这是一个示例(因为您没有提供完整的实现):

分段

private val googleRegisterResult =
    registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
            result.checkResultAndExecute {
                val task = GoogleSignIn.getSignedInAccountFromIntent(data)
                val account = task.getResult(ApiException::class.java)
                loginViewModel.onEvent(LoginRegistrationEvent.SignInWithGoogle(account))
            }.onFailure { e -> toast("Error: ${e.message}") }
        }

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
     super.onViewCreated(view, savedInstanceState)
     myGoogleSignInButton.setOnClickListener {
        googleRegisterResult.launch(viewModel.googleSignInClient.signInIntent)
    }
}

然后,在您的视图模型中,您可以像往常一样处理登录,唯一的区别是,您不再需要RC_SIGN_IN

视图模型示例

class YourViewModel : ViewModel() {
    fun onEvent(event: LoginRegistrationEvent) {
       when(event) {
         is LoginRegistrationEvent.SignInWithGoogle -> {
              viewModelScope.launch {
                     val credential = GoogleAuthProvider.getCredential(event.account.idToken)
                     Firebase.auth.signInWithCredential(credential).await()
             }
         }
      }
    }
}

为了让我的生活更轻松,我创建了一个扩展函数,它检查登录是否成功,然后执行一段代码(在这种情况下,获取帐户),同时缓存任何异常。此外,在您的块内,您可以访问 ActivityResult 的实例this

inline fun ActivityResult.checkResultAndExecute(block: ActivityResult.() -> Unit) =
    if (resultCode == Activity.RESULT_OK) runCatching(block)
    else Result.failure(Exception("Something went wrong"))

推荐阅读