14、错误码与异常处理:常见错误码列表、异常捕获、用户友好提示
做指纹识别开发,最怕什么?
不是功能实现不了,而是用户在那戳了半天,手机没反应,或者弹个莫名其妙的错误。用户直接懵了,然后给你一个差评。
我早期做的一个项目,就吃过这个亏。那时候刚接触生物识别,觉得能调通接口就万事大吉了。结果上线后,用户反馈“指纹用不了”,排查半天,原来是手机硬件不支持,但我没做任何提示。用户以为手机坏了。
所以,错误码和异常处理,不是可有可无的补充。它是用户体验的最后一道防线。今天我们就来把这套防线彻底建好。
14.1 常见错误码列表
Android 的 BiometricPrompt 在认证失败时,会通过 AuthenticationCallback 返回一个错误码。这些错误码定义在 BiometricConstants 类里。我习惯把它们分成三类:硬件问题、用户操作问题、系统内部问题。
下面这张图,是我自己整理的分类逻辑,你可以参考一下:
下面我把最常用的几个错误码列出来,并附上我个人的处理建议。
| 错误码 | 含义 | 常见原因 | 我建议的处理方式 |
|---|---|---|---|
ERROR_NO_BIOMETRICS |
设备没有录入任何生物特征 | 用户未录入指纹/人脸 | 引导用户去「设置」中录入 |
ERROR_HW_UNAVAILABLE |
硬件暂时不可用 | 传感器被占用、正在初始化 | 提示稍后再试,不要频繁重试 |
ERROR_HW_NOT_PRESENT |
设备没有指纹/人脸硬件 | 低端机、平板不支持 | 直接隐藏指纹选项,改用密码 |
ERROR_LOCKOUT |
尝试次数过多,暂时锁定 | 连续失败5次左右 | 显示倒计时,30秒后自动解锁 |
ERROR_LOCKOUT_PERMANENT |
永久锁定 | 连续失败太多次 | 必须用密码/PIN解锁 |
ERROR_TIMEOUT |
操作超时 | 用户长时间未操作 | 自动关闭对话框,让用户重新触发 |
ERROR_USER_CANCELED |
用户主动取消 | 用户点了「取消」或按了返回 | 无需额外提示,正常结束流程 |
ERROR_VENDOR |
厂商自定义错误 | 各家手机特有的问题 | 记录日志,提示「请重试」 |
ERROR_VENDOR 的详细信息打印到日志里。因为不同厂商的错误码含义差别很大,比如华为和小米对同一个错误码的解释可能完全不同。上线前,最好找几台主流机型都测一遍。
14.2 异常捕获:别让 App 闪退
说实话,BiometricPrompt 本身不太会抛出运行时异常。但它的回调方法是在主线程执行的。如果你在回调里做了耗时操作,或者不小心抛了个 NullPointerException,那 App 直接就崩了。
我曾经就犯过这个错。在 onAuthenticationError 里更新 UI,结果那个 View 已经被销毁了,直接闪退。用户一脸懵逼。
所以,我现在的做法是:所有回调方法里,都包一层 try-catch。尤其是 onAuthenticationError 和 onAuthenticationFailed。
来看一个我常用的模板:
private final BiometricPrompt.AuthenticationCallback callback =
new BiometricPrompt.AuthenticationCallback() {
@Override
public void onAuthenticationError(int errorCode, CharSequence errString) {
try {
// 先检查 Activity 是否存活
if (isDestroyed() || isFinishing()) {
return;
}
handleError(errorCode, errString);
} catch (Exception e) {
// 兜底:记录日志,不要崩溃
Log.e("Biometric", "onAuthenticationError异常", e);
}
}
@Override
public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) {
try {
// 处理成功逻辑
onBiometricSuccess();
} catch (Exception e) {
Log.e("Biometric", "onAuthenticationSucceeded异常", e);
}
}
@Override
public void onAuthenticationFailed() {
try {
// 指纹不匹配,提示用户
showFailedMessage();
} catch (Exception e) {
Log.e("Biometric", "onAuthenticationFailed异常", e);
}
}
};
onAuthenticationSucceeded 里的业务逻辑,如果出错了,应该让开发者看到崩溃日志,而不是静默吞掉。我这里的 try-catch 只是为了保护 UI 操作不导致闪退。
14.3 用户友好提示:别让用户猜
错误码是给开发者看的。用户不需要知道 ERROR_LOCKOUT 是什么。他们只想知道:现在该怎么办?
我总结了一个原则:提示信息要包含「原因 + 行动」。比如:
- ❌ 错误:
ERROR_HW_UNAVAILABLE - ✅ 友好提示:「指纹传感器暂时不可用,请稍后再试」
再比如:
- ❌ 错误:
ERROR_NO_BIOMETRICS - ✅ 友好提示:「您还没有录入指纹,请前往设置添加」
下面是我项目中实际用到的提示文案,你可以直接参考:
| 错误码 | 用户提示文案 | 附加操作 |
|---|---|---|
ERROR_NO_BIOMETRICS |
「未录入指纹,是否前往设置添加?」 | 提供「去设置」按钮,跳转指纹录入页 |
ERROR_HW_UNAVAILABLE |
「指纹识别暂时不可用,请稍后重试」 | 自动关闭对话框,3秒后可重新触发 |
ERROR_LOCKOUT |
「尝试次数过多,请30秒后再试」 | 显示倒计时,倒计时结束后自动恢复 |
ERROR_LOCKOUT_PERMANENT |
「指纹已被锁定,请使用密码验证」 | 自动切换到密码输入界面 |
ERROR_TIMEOUT |
「操作超时,请重新尝试」 | 自动关闭对话框,无额外操作 |
ERROR_USER_CANCELED |
不提示(用户主动取消) | 正常结束流程 |
ERROR_VENDOR |
「指纹识别异常,请重试」 | 记录日志,方便排查 |
14.4 避坑指南:我踩过的几个坑
最后,分享几个我实际项目中遇到的坑,希望能帮你省点时间。
- 坑一: 我曾经在
onAuthenticationError里直接弹 Dialog,结果因为 Activity 已经 onPause,Dialog 弹不出来,还报了WindowManager.BadTokenException。解决方案:弹 Dialog 前先检查 Activity 状态。 - 坑二: 有些手机在
ERROR_HW_UNAVAILABLE之后,会连续回调多次。如果你不做去重处理,用户会看到一堆提示。我习惯用一个标志位isErrorHandled来控制。 - 坑三:
ERROR_LOCKOUT_PERMANENT在不同厂商手机上触发条件不一样。有的手机连续失败5次就永久锁定,有的要10次。所以,不要硬编码次数,而是根据错误码来响应。
嗯,错误码这块其实不难,但细节很多。你只要把每个错误码对应的用户提示都写好,再包一层 try-catch,基本就稳了。下次用户再遇到问题,至少不会一脸茫然地来骂你。