将 Firebase 电话身份验证与协程结合使用

时间:2021-03-17 10:26:40

标签: android firebase kotlin firebase-authentication kotlin-coroutines

我想使用 Firebase 电话身份验证在我的应用中创建签名活动。身份验证分为三个阶段:

  1. 使用 PhoneAuthProvider.verifyPhoneNumber(options) 发送验证码
  2. 使用 PhoneAuthProvider.getCredential(verificationId!!, code) 验证代码
  3. 使用 auth.signInWithCredential(credential) 为用户登录

我想使用协程来处理签名过程。我知道如何使用 await() 处理代码验证,它包装了 Task 返回的 auth.signInWithCredential(credential)

我的问题是 PhoneAuthProvider.verifyPhoneNumber(options) 函数,它是一个 void 函数。我必须使用回调来处理这个方法。

val options = PhoneAuthOptions.newBuilder(auth)
      .setPhoneNumber(phoneNumber)
      .setTimeout(60L, TimeUnit.SECONDS)
      .setCallbacks(callback)
      .build()
PhoneAuthProvider.verifyPhoneNumber(options)

其中 callbacks 是:

callbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks(){
            override fun onVerificationCompleted(credential: PhoneAuthCredential) {
                Timber.i("onVerificationCompleted:$credential")
                signInWithPhoneAuthCredential(credential)
            }

            override fun onVerificationFailed(e: FirebaseException) {
                Timber.i(e,"onVerificationFailed")
            }

            override fun onCodeSent(verificationId: String, token: PhoneAuthProvider.ForceResendingToken) {
                Timber.i("onCodeSent:$verificationId")
                storedVerificationId = verificationId
                resendToken = token
            }
        }

问题是:有没有办法将 await()verifyPhoneNumber 函数一起使用? 否则,我如何使用带有回调的协程来阻止函数,直到回调触发?

1 个答案:

答案 0 :(得分:1)

您可以使用 suspendCoroutine 将 Firebase 回调包装到协程挂起函数中,如下所示:

sealed class PhoneAuthResult {
    data class VerificationCompleted(val credentials: PhoneAuthCredential) : PhoneAuthResult()
    data class CodeSent(val verificationId: String, val token: PhoneAuthProvider.ForceResendingToken)
        : PhoneAuthResult()
}

private suspend fun performPhoneAuth(
    phoneNumber: String,
    firebaseAuth: FirebaseAuth): PhoneAuthResult = 
    suspendCoroutine { cont ->
        val callback = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
            override fun onVerificationCompleted(credential: PhoneAuthCredential) {
                Timber.i("onVerificationCompleted:$credential")
                cont.resume(
                    PhoneAuthResult.VerificationCompleted(credential)
                )
            }

            override fun onVerificationFailed(e: FirebaseException) {
                Timber.i(e, "onVerificationFailed")
                cont.resumeWithException(e)
            }

            override fun onCodeSent(verificationId: String, token: PhoneAuthProvider.ForceResendingToken) {
                Timber.i("onCodeSent:$verificationId")
                cont.resume(
                    PhoneAuthResult.CodeSent(verificationId, token)
                )
            }
        }
        
        val options = PhoneAuthOptions.newBuilder(firebaseAuth)
            .setPhoneNumber(phoneNumber)
            .setTimeout(60L, TimeUnit.SECONDS)
            .setCallbacks(callback)
            .build()

        PhoneAuthProvider.verifyPhoneNumber(options)
    }