9、Android 10以下兼容处理:使用FingerprintManagerCompat、AndroidX兼容库、版本判断逻辑
好,咱们接着聊。上一章我讲了Android 10以上的生物识别API,那Android 10以下的设备怎么办?
说实话,这才是真正的「硬仗」。我翻过不少项目的代码,发现很多人在低版本兼容上栽了跟头。有的直接crash,有的指纹识别弹不出来,有的干脆不支持人脸——嗯,这些坑我都踩过。
为什么需要兼容处理?
Android的生物识别API经历了几个阶段:
- Android 6.0 (API 23):首次引入FingerprintManager,只支持指纹
- Android 9.0 (API 28):引入BiometricPrompt,支持人脸+指纹+虹膜
- Android 10 (API 29):BiometricPrompt正式稳定,废弃旧API
你想想看,如果你的App要覆盖Android 6到Android 13的用户,那你就得同时处理三套API。我见过最离谱的项目,直接只在Android 10以上跑,低版本用户全部弹Toast「您的设备不支持」——这显然不行。
核心思路:运行时判断API版本,高版本用BiometricPrompt,低版本用FingerprintManagerCompat + AndroidX兼容库。
第一步:引入AndroidX兼容库
我个人习惯用AndroidX的biometric库,它已经帮我们封装好了大部分兼容逻辑。但注意,这个库只支持API 28以上。对于API 23-27,我们还得自己处理。
在build.gradle里添加依赖:
dependencies {
// AndroidX 生物识别库(API 28+)
implementation 'androidx.biometric:biometric:1.2.0-alpha05'
// 兼容库(用于FingerprintManagerCompat)
implementation 'androidx.core:core:1.9.0'
}
小提示:biometric库的1.2.0版本开始,已经内置了对FingerprintManagerCompat的封装。但如果你要自己控制细节,还是建议手动判断版本。
第二步:版本判断逻辑
嗯,这里要写一个工具类。我习惯把它叫做BiometricUtils,专门处理版本判断和兼容。
public class BiometricUtils {
/**
* 判断当前设备是否支持生物识别
*/
public static boolean isBiometricSupported(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// Android 9+ 使用BiometricManager
BiometricManager manager = BiometricManager.from(context);
return manager.canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS;
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Android 6-8 使用FingerprintManagerCompat
FingerprintManagerCompat compat = FingerprintManagerCompat.from(context);
return compat.isHardwareDetected() && compat.hasEnrolledFingerprints();
} else {
return false;
}
}
/**
* 获取可用的认证方式
*/
public static int getAvailableAuthenticators(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
BiometricManager manager = BiometricManager.from(context);
return manager.getAvailableAuthenticators();
} else {
// 低版本只支持指纹
return BiometricManager.Authenticators.BIOMETRIC_FINGERPRINT;
}
}
}
这里有个细节:FingerprintManagerCompat只支持指纹,不支持人脸。所以如果你在Android 6-8的设备上想做人脸识别,那基本没戏——硬件层面就不支持。我当年在一个项目里,产品经理非要让Android 7的手机支持人脸解锁,我跟他解释了半天「硬件不支持」,最后他妥协了。
第三步:使用FingerprintManagerCompat进行指纹认证
对于Android 6-8的设备,我们只能用指纹。代码长这样:
public class LegacyFingerprintHelper {
private FingerprintManagerCompat manager;
private CancellationSignal cancellationSignal;
public LegacyFingerprintHelper(Context context) {
manager = FingerprintManagerCompat.from(context);
}
public void startAuth(FingerprintManagerCompat.AuthenticationCallback callback) {
if (cancellationSignal != null && !cancellationSignal.isCanceled()) {
cancellationSignal.cancel();
}
cancellationSignal = new CancellationSignal();
// 注意:这里需要API 23+,且用户已录入指纹
manager.authenticate(null, 0, cancellationSignal, callback, null);
}
public void stopAuth() {
if (cancellationSignal != null) {
cancellationSignal.cancel();
cancellationSignal = null;
}
}
}
避坑指南:我曾经在authenticate()方法里传了null的CryptoObject,结果在某些华为手机上直接闪退。后来查文档才发现,部分厂商对CryptoObject有强校验。建议至少传一个简单的null,但最好用KeyGenParameterSpec生成一个。
第四步:统一调用入口
为了让上层调用者不用关心版本,我封装了一个统一的认证类:
public class BiometricAuthManager {
private Context context;
public BiometricAuthManager(Context context) {
this.context = context.getApplicationContext();
}
public void authenticate(BiometricAuthCallback callback) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// 高版本使用BiometricPrompt
showBiometricPrompt(callback);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// 低版本使用FingerprintManagerCompat
showFingerprintDialog(callback);
} else {
callback.onError("设备不支持生物识别");
}
}
private void showBiometricPrompt(BiometricAuthCallback callback) {
BiometricPrompt.PromptInfo info = new BiometricPrompt.PromptInfo.Builder()
.setTitle("验证身份")
.setSubtitle("请使用指纹或人脸验证")
.setNegativeButtonText("取消")
.build();
BiometricPrompt prompt = new BiometricPrompt(
(FragmentActivity) context,
ContextCompat.getMainExecutor(context),
new BiometricPrompt.AuthenticationCallback() {
@Override
public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) {
callback.onSuccess();
}
@Override
public void onAuthenticationError(int errorCode, CharSequence errString) {
callback.onError(errString.toString());
}
@Override
public void onAuthenticationFailed() {
callback.onFailed();
}
});
prompt.authenticate(info);
}
private void showFingerprintDialog(BiometricAuthCallback callback) {
// 这里可以弹出自定义指纹对话框
// 或者直接调用FingerprintManagerCompat
LegacyFingerprintHelper helper = new LegacyFingerprintHelper(context);
helper.startAuth(new FingerprintManagerCompat.AuthenticationCallback() {
@Override
public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
callback.onSuccess();
}
@Override
public void onAuthenticationError(int errMsgId, CharSequence errString) {
callback.onError(errString.toString());
}
@Override
public void onAuthenticationFailed() {
callback.onFailed();
}
});
}
public interface BiometricAuthCallback {
void onSuccess();
void onError(String error);
void onFailed();
}
}
核心逻辑流程图
下面这张图,是我整理的整体兼容策略。你看一眼就明白了:
常见问题与避坑
| 问题 | 原因 | 解决方案 |
|---|---|---|
| FingerprintManagerCompat找不到类 | 没有引入AndroidX core库 | 添加implementation 'androidx.core:core:1.9.0' |
| 低版本设备上弹不出指纹对话框 | 没有检查hasEnrolledFingerprints() |
先检查用户是否已录入指纹 |
| 部分厂商设备上CryptoObject为null时崩溃 | 厂商对CryptoObject有强校验 | 使用KeyGenParameterSpec生成CryptoObject |
| Android 9设备上BiometricPrompt不显示人脸选项 | 没有设置setAllowedAuthenticators() |
显式指定BIOMETRIC_STRONG | BIOMETRIC_WEAK |
我的经验:在低版本兼容上,我建议你多做一步——在用户点击「指纹验证」之前,先调用isBiometricSupported()检查。如果返回false,直接弹Toast提示「您的设备不支持」,而不是让用户点了之后才报错。用户体验会好很多。
总结一下
Android 10以下的兼容处理,说白了就是三件事:
- 版本判断:用
Build.VERSION.SDK_INT区分API 28+、API 23-27、API 22- - API选择:高版本用BiometricPrompt,低版本用FingerprintManagerCompat
- 统一封装:对外暴露一个接口,内部根据版本走不同分支
嗯,这套方案我在好几个项目里验证过,覆盖了从Android 6到Android 13的机型,没出过兼容性问题。你照着这个思路写,应该不会踩坑。
最后提醒一句:千万不要在Android 6以下的设备上调用任何生物识别API——那些设备连指纹硬件都没有,调用就是crash。老老实实走密码验证吧。