如何将 registerForActivityResult 与 StartIntentSenderForResult 合同一起使用?

Posted

技术标签:

【中文标题】如何将 registerForActivityResult 与 StartIntentSenderForResult 合同一起使用?【英文标题】:How do I use registerForActivityResult with StartIntentSenderForResult contract? 【发布时间】:2021-09-21 13:03:05 【问题描述】:

我正在编写一个 Kotlin 应用程序并使用 Firebase 进行身份验证。 由于onActivityResult 现在已弃用,我正在尝试迁移我的应用程序以使用registerForActivityResult。我有一个指向 Google 帐户功能的链接,它以 Google 登录流程开始,如 here 所示。我的代码:

    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 在片段的onCreateView 中被调用,showLinkWithGoogle 在用户点击屏幕上的按钮时被调用。这完美地工作。 我使用registerForActivityResult 查找了一个示例,我发现最好的示例位于this 页面的底部。我添加了这段代码:

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

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

但意识到IntentSenderRequest.Builder 需要IntentSender 而不是Intent。我没有找到任何关于如何从Intent 构建IntentSender 的示例,也没有找到从我的GoogleSignInClient 获取的方法。 谁能提供一个使用registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult())的完整示例?

非常感谢!

【问题讨论】:

【参考方案1】:

对于这个用例,您不需要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

ViewModel 示例

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()
             
         
      
    

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

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

【讨论】:

好的,我喜欢这个解决方案——它有效而且看起来很干净。谢谢! :) 这让我想知道为什么New Google Sign-In API doc 指向StartIntentSenderForResult 结果合同...... @OmerLevy 文档大部分时间都是错误的,会导致一些愚蠢的解决方案。只是一些谷歌的东西 @Andrew 我正在学习 android Studio/Kotlin 编程,使用的课程我发现有过时的材料。我在这里尝试遵循您的逻辑,但我无法弄清楚一件事。 loginViewModel 从何而来?据我所知,develop.android.com 上没有。谷歌搜索表明它来自 Github。你能详细说明一下吗? @N.Barrett LoginViewModel 只是一个例子,如何在 MVVM 环境中集成registerForActivityResult

以上是关于如何将 registerForActivityResult 与 StartIntentSenderForResult 合同一起使用?的主要内容,如果未能解决你的问题,请参考以下文章

如何将CString转换成wstring

如何将Ios文件上传到

Qt如何将文字变成图片?

如何将Bitmap保存为本地图片文件?

在MATLAB中如何将图导出

ASP如何将SQLSERVER数据导出到DBF(VF)