如何将 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 合同一起使用?的主要内容,如果未能解决你的问题,请参考以下文章