在 Android 上处理 Firebase 电话号码验证错误

如果对 Firebase PNV 库的调用失败,该库会报告 FirebasePhoneNumberVerificationException。本页面列出了该异常可能携带的所有错误代码、每个错误代码的发生时间以及应用应采取的措施。

本页假设您已按照在 Android 上开始使用 Firebase Phone Number Verification 中的说明集成了 Firebase PNV。

错误的报告方式

  • 异步方法(getVerificationSupportInfo()、getVerifiedPhoneNumber() 和自定义流程方法)会返回 Task。如果这些操作失败,Task 将失败并显示 FirebasePhoneNumberVerificationException,您会在 addOnFailureListener 中收到该错误。

  • enableTestSession() 是同步的。它会直接抛出 FirebasePhoneNumberVerificationException。

阅读异常的 errorCode,了解出了什么问题。Firebase PNV 代码是 FirebasePnvStatusCodes 类中的常量。如果失败是由 Google Play 服务引起的,errorCode 也可以是 CommonStatusCodes 值,例如 NETWORK_ERROR。

设备或 SIM 卡不受支持不属于错误。getVerificationSupportInfo() 成功,并针对该 SIM 卡将 isSupported() 报告为 false,而 getReason() 会告诉您原因。请参阅不支持的设备和 SIM 卡。

错误代码

测试会话设置

这些错误由 enableTestSession() 同步抛出。

错误代码 原因 建议采取的操作
TEST_SESSION_ALREADY_ENABLED
(55508)
在同一应用进程中多次调用了 enableTestSession()。FirebasePhoneNumberVerification.getInstance() 每次都会返回同一实例,因此当调用它的 Activity 重新创建时,也会发生这种情况。 每个进程调用一次 enableTestSession(),例如在 Application.onCreate() 中。请参阅在测试模式下初始化库。
INVALID_TEST_NUMBER_ID
(55507)
传递给 enableTestSession() 的测试令牌为空。 确保您的 build 传递您在 Firebase 控制台中生成的令牌,并且仅在令牌不为空时调用 enableTestSession()。

验证

这些错误会导致 getVerifiedPhoneNumber() 返回的 Task 失败。

错误代码 原因 建议采取的操作
CREDENTIAL_MANAGER_ERROR
(55506)
Android Credential Manager 未返回电话号码。如果异常的 cause 为 GetCredentialCancellationException,则用户很可能关闭了权限请求页面。 提供其他电话号码验证方式,例如短信。请勿自动重试,因为用户会再次看到权限请求页面。
CARRIER_NOT_SUPPORTED
(55501)
所选 SIM 卡的运营商不受支持,或者设备没有验证该 SIM 卡所需的订阅信息。 回退到其他验证方法,例如短信。
UNSUPPORTED_OPERATION
(55505)
Firebase PNV 无法在设备上处理此请求。 回退到其他验证方法,例如短信。
PREFLIGHT_CHECK_FAILED
(55504)
在显示权限请求页面之前,Firebase PNV 后端无法创建验证请求。 改用其他验证方法,例如短信。如果每个请求都会发生这种情况,请检查您的应用是否设置正确(请参阅升级到生产模式)。
INTEGRITY_CHECK_FAILED
(55503)
设备或应用未通过完整性检查。 回退到其他验证方法,例如短信。
INVALID_DIGITAL_CREDENTIAL_RESPONSE
(55502)
无法读取来自 Credential Manager 的响应,或无法将其交换为已验证的电话号码。 回退到其他验证方法,例如短信。
INVALID_TEST_NUMBER_ID
(55507)
在测试模式下,Firebase PNV 后端拒绝了测试令牌,例如因为令牌已过期。测试令牌的 TTL 为 7 天。被拒绝的测试令牌通常会报告此代码;如果您在测试模式下看到其他错误,请检查您的令牌是否为最新。 在 Firebase 控制台中生成新的测试令牌,然后重新构建应用。
ACTIVITY_CONTEXT_REQUIRED
(55509)
传递给 getVerifiedPhoneNumber() 的 Context 不是 Activity。该方法需要 Activity 才能显示权限请求页面。 传递当前 Activity。这是应用中的 bug,而不是要在运行时处理的条件。

支持检查

只有在检查本身无法运行时,getVerificationSupportInfo() 返回的 Task 才会失败。在这种情况下,errorCode 是 Google Play 服务 CommonStatusCodes 值或 CARRIER_NOT_SUPPORTED。将设备视为不受支持,并回退到其他验证方法(例如短信)。

启用测试会话后,getVerificationSupportInfo() 不会与 Firebase PNV 后端联系,并且始终会将测试 SIM 卡报告为受支持,即使测试令牌已过期也是如此。

自定义流程

如果您使用自定义流程而不是 getVerifiedPhoneNumber():

  • getDigitalCredentialPayload() 失败,并显示 PREFLIGHT_CHECK_FAILED;如果后端拒绝您的测试令牌,则显示 INVALID_TEST_NUMBER_ID。
  • exchangeCredentialResponseForPhoneNumber() 失败并显示 INVALID_DIGITAL_CREDENTIAL_RESPONSE,或者如果后端拒绝您的测试令牌,则失败并显示 INVALID_TEST_NUMBER_ID。
  • 您自己对 Credential Manager 的调用会抛出 GetCredentialException,您需要直接处理该异常。

不支持的设备和 SIM 卡

如果 SIM 卡的 isSupported() 为 false,getReason() 会返回以下 VerificationSupportStatus 值之一:

值 含义
INCAPABLE_DUE_TO_CARRIER_UNSUPPORTED 不支持 SIM 卡的运营商。请参阅支持的运营商。
INCAPABLE_DUE_TO_ANDROID_VERSION 设备搭载的 Android 版本低于 Android 9(API 级别 28)。
INCAPABLE_DUE_TO_SIM_STATE SIM 卡尚未准备就绪。已锁定或仍在加载的 SIM 卡也可能会报告 INCAPABLE_DUE_TO_CARRIER_UNSUPPORTED,因为系统会先检查运营商。

在每种情况下,请针对该 SIM 卡使用其他验证方法,例如短信。

示例

以下示例处理了典型应用在调用 getVerifiedPhoneNumber() 时需要区分的错误:

Kotlin

import android.util.Log
// Credential Manager is included with the Firebase PNV library.
import androidx.credentials.exceptions.GetCredentialCancellationException
import com.google.firebase.pnv.FirebasePhoneNumberVerification
import com.google.firebase.pnv.FirebasePhoneNumberVerificationException
import com.google.firebase.pnv.FirebasePnvStatusCodes

private const val TAG = "PhoneVerification"

// In your Activity:
private fun verifyPhoneNumber() {
    FirebasePhoneNumberVerification.getInstance()
        .getVerifiedPhoneNumber(this)
        .addOnSuccessListener { result ->
            // Send result.getToken() to your backend.
        }
        .addOnFailureListener { e -> handleFpnvError(e) }
}

private fun handleFpnvError(e: Exception) {
    if (e !is FirebasePhoneNumberVerificationException) {
        Log.w(TAG, "Firebase PNV failed", e)
        showSmsVerification()
        return
    }
    when (e.errorCode) {
        FirebasePnvStatusCodes.CREDENTIAL_MANAGER_ERROR -> {
            if (e.cause is GetCredentialCancellationException) {
                // The user dismissed the consent screen.
            }
            showSmsVerification()
        }
        FirebasePnvStatusCodes.INVALID_TEST_NUMBER_ID -> {
            // Test mode only: generate a new test token.
            Log.e(TAG, "Firebase PNV test token rejected", e)
        }
        FirebasePnvStatusCodes.ACTIVITY_CONTEXT_REQUIRED -> {
            // App bug: pass an Activity to getVerifiedPhoneNumber().
            Log.e(TAG, "Firebase PNV needs an Activity context", e)
        }
        else -> {
            // Carrier not supported, network errors, and other failures.
            Log.w(TAG, "Firebase PNV failed with error code ${e.errorCode}", e)
            showSmsVerification()
        }
    }
}

在此示例中,showSmsVerification() 是应用的现有电话号码验证流程。

后续步骤