18、指纹认证与通知栏:创建通知渠道、显示认证通知、通知点击处理、锁屏状态下的认证
通知栏和指纹认证,这两个功能单独看都不算复杂。但把它们结合起来,嗯,这里就有不少门道了。
我个人习惯把这种组合场景叫做「锁屏下的快捷操作」。用户手机锁着,收到一条通知,点一下,指纹一按,直接跳转到应用内部某个敏感页面。这个流程做得好,用户体验会非常丝滑;做得不好,用户可能连通知都看不到。
今天我们就来拆解这个流程。说白了,就是三件事:通知怎么发、通知怎么点、点了之后怎么认证。
18.1 创建通知渠道:Android 8.0 的必修课
从 Android 8.0(API 26)开始,所有通知都必须绑定一个通知渠道(NotificationChannel)。如果你不创建渠道,通知根本不会显示。我在项目中遇到过好几次这种问题——测试机是 Android 7.0 没事,换到 Android 9.0 就收不到通知,排查了半天才发现是渠道没建。
创建渠道的代码其实很简单,但有几个细节要注意:
// 创建通知渠道
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String channelId = "fingerprint_auth_channel";
String channelName = "指纹认证通知";
String channelDescription = "用于显示指纹认证相关的通知";
NotificationChannel channel = new NotificationChannel(
channelId,
channelName,
NotificationManager.IMPORTANCE_HIGH // 重要级别
);
channel.setDescription(channelDescription);
channel.setLockscreenVisibility(NotificationCompat.VISIBILITY_PUBLIC);
NotificationManager notificationManager =
getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
这里有个关键点:setLockscreenVisibility 方法。它决定了通知在锁屏界面上的显示方式。
| 可见性级别 | 含义 | 适用场景 |
|---|---|---|
| VISIBILITY_PUBLIC | 锁屏上显示全部内容 | 普通通知,无敏感信息 |
| VISIBILITY_PRIVATE | 锁屏上只显示图标,隐藏内容 | 包含用户隐私的通知 |
| VISIBILITY_SECRET | 锁屏上完全不显示 | 高度敏感的通知 |
对于指纹认证场景,我建议使用 VISIBILITY_PUBLIC。为什么呢?因为用户需要在锁屏状态下看到通知内容,才能决定要不要点击认证。如果你设成 PRIVATE,用户解锁后还得再点一次通知,多了一步操作,体验就差了。
18.2 显示认证通知:带上 PendingIntent
通知本身没什么特别的,但我们要在通知上绑定一个 PendingIntent,这样用户点击通知时才能触发指纹认证流程。
// 构建通知
Intent intent = new Intent(this, FingerprintAuthActivity.class);
intent.putExtra("need_auth", true); // 标记需要指纹认证
PendingIntent pendingIntent = PendingIntent.getActivity(
this,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.ic_fingerprint)
.setContentTitle("请验证指纹")
.setContentText("点击此处进行指纹认证")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(pendingIntent)
.setAutoCancel(true); // 点击后自动移除通知
NotificationManagerCompat notificationManager =
NotificationManagerCompat.from(this);
notificationManager.notify(1001, builder.build());
这里有个小坑:FLAG_IMMUTABLE 是 Android 12 之后强制要求的。如果你不加上这个 flag,在 Android 12 以上设备上会直接崩溃。我曾经在适配 Android 12 时踩过这个坑,日志里报了个 SecurityException,查了半天才发现是 PendingIntent 的问题。
18.3 通知点击处理:跳转与认证的衔接
用户点击通知后,会跳转到我们指定的 Activity。但这个 Activity 不能直接展示内容,它要先走一遍指纹认证流程。
我的做法是这样的:在 Activity 的 onCreate 方法中判断 Intent 是否携带了认证标记,如果有,就立即启动指纹认证。
public class FingerprintAuthActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean needAuth = getIntent().getBooleanExtra("need_auth", false);
if (needAuth) {
// 显示指纹认证界面
showFingerprintDialog();
} else {
// 正常启动,不要求认证
showNormalContent();
}
}
private void showFingerprintDialog() {
// 这里调用我们之前章节讲过的 BiometricPrompt
BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
.setTitle("指纹认证")
.setSubtitle("请验证您的指纹以查看内容")
.setNegativeButtonText("取消")
.build();
BiometricPrompt biometricPrompt = new BiometricPrompt(
this,
ContextCompat.getMainExecutor(this),
new BiometricPrompt.AuthenticationCallback() {
@Override
public void onAuthenticationSucceeded(
BiometricPrompt.AuthenticationResult result) {
// 认证成功,显示内容
showSensitiveContent();
}
@Override
public void onAuthenticationError(int errorCode,
CharSequence errString) {
// 认证失败,关闭页面
finish();
}
}
);
biometricPrompt.authenticate(promptInfo);
}
}
你想想看,这个流程其实很自然:用户点击通知 → 进入 Activity → 弹出指纹对话框 → 认证通过 → 显示内容。每一步都是用户主动触发的,不会有突兀感。
18.4 锁屏状态下的认证:特殊处理
锁屏状态下调用指纹认证,有个很头疼的问题:BiometricPrompt 的对话框可能被系统锁屏界面挡住。
为什么会这样?因为 BiometricPrompt 本质上是一个系统级别的对话框,它和锁屏界面属于同一个窗口层级。如果手机处于锁屏状态,系统会优先显示锁屏界面,你的指纹对话框可能被压在下面,用户根本看不到。
我在项目中遇到过这个情况:测试的时候手机亮着屏,指纹对话框弹得好好的。结果把手机锁屏再试,通知点进去后一片漆黑,用户不知道要干嘛。后来才发现是锁屏界面把对话框挡住了。
解决方案有两种:
- 方案一:先解锁再认证
在启动 Activity 时,先请求用户解锁屏幕。解锁成功后,再弹出指纹对话框。 - 方案二:使用 KeyguardManager
通过 KeyguardManager 判断当前是否处于锁屏状态,如果是,先解除锁屏再认证。
我个人更推荐方案一,因为它更符合用户预期。具体做法是在 Activity 的 onCreate 中加上锁屏检测:
KeyguardManager keyguardManager =
(KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
if (keyguardManager.isKeyguardLocked()) {
// 手机处于锁屏状态,先请求解锁
Intent unlockIntent = keyguardManager.createConfirmDeviceCredentialIntent(
"解锁手机",
"请先解锁以进行指纹认证"
);
if (unlockIntent != null) {
startActivityForResult(unlockIntent, REQUEST_CODE_UNLOCK);
}
} else {
// 手机已解锁,直接弹出指纹认证
showFingerprintDialog();
}
这里要注意:createConfirmDeviceCredentialIntent 会弹出一个系统级的解锁界面,用户输入密码或图案解锁后,会通过 onActivityResult 返回结果。我们在 onActivityResult 中判断解锁成功后再启动指纹认证。
18.5 整体流程梳理
说了这么多,我们来画一张图,把整个流程串起来。这样你看起来会更清楚。
从这张图可以看得很清楚:整个流程的核心就是「通知 → 点击 → 锁屏判断 → 认证 → 显示内容」。每一步都是环环相扣的,任何一个环节出问题,用户体验都会打折扣。
最后提醒一句:锁屏状态下的指纹认证一定要做充分测试。不同厂商的 Android 系统对锁屏和 BiometricPrompt 的处理方式可能不一样。我建议你在至少 3-5 款不同品牌的手机上测试这个流程,确保万无一失。
核心要点回顾:
- 通知渠道必须设置锁屏可见性为 PUBLIC
- PendingIntent 要加上 FLAG_IMMUTABLE
- 锁屏状态下先请求解锁,再弹出指纹认证
- 多机型测试,避免厂商差异导致的问题
好了,这一章的内容就到这里。指纹认证与通知栏的结合,说白了就是让用户在锁屏状态下也能安全快捷地访问敏感内容。把握好「安全」和「便捷」的平衡点,你的应用就能给用户带来很好的体验。
公众号:蓝海资料掘金营,微信deep3321