将 Firebase Phone 身份验证与协程一起使用

Use Firebase Phone Authentication with Coroutines

我想在我的应用程序中使用 Firebase phone 身份验证创建签名 activity。身份验证分为三个阶段:

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

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

我的问题是 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函数一起使用? 否则,我如何使用带有回调的协程来阻止函数直到回调被触发?

您可以使用 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)
    }