字段脱敏能解决大部分问题,但有些页面太敏感了,只隐藏几个数字还不够。这个项目还演示了系统防窥蒙层:状态触发后,直接让系统帮你盖住页面。
项目地址:https://gitcode.com/HarmonyOS_Samples/AntiPeep

先看效果
触发防窥并打开蒙层开关后,会出现系统防窥蒙层:

折叠屏上也能看到对应效果:

这不是应用自己写的半透明 Stack,而是通过系统 API 拉起的防窥蒙层。
蒙层开关只是应用侧控制
页面里有一个开关:
Toggle({ type: ToggleType.Switch, isOn: false })
.selectedColor($r('sys.color.comp_background_emphasize'))
.switchPointColor($r('sys.color.font_on_primary'))
.onChange((isOn: boolean) => {
this.isToggleOpened = isOn;
})
这个开关控制的是应用要不要在 HIDE 状态下调用系统蒙层。它不是系统防窥总开关,别搞混。
系统防窥总开关在系统设置里;页面里的开关只是这个 Demo 给用户提供的体验选项。
真正调用蒙层的函数
封装在 AntiPeepUtils.ets:
export function showSystemMaskLayer(windowId: number): Promise<boolean> {
return new Promise((resolve) => {
try {
if (canUseAntiPeep()) {
dlpAntiPeep.setAntiPeepMaskLayer(windowId).catch((err: BusinessError) => {
Logger.error(TAG, `Execute setAntiPeepMaskLayer failed. error code:${err.code}, error message:${err.message}`);
resolve(false);
}).then(() => {
Logger.info(TAG, `setAntiPeepMaskLayer success`);
resolve(true);
})
} else {
resolve(false);
}
} catch (err) {
Logger.error(TAG, `Call setAntiPeepMaskLayer failed. ${JSON.stringify(err)}`);
resolve(false);
}
});
}
核心 API 是:
dlpAntiPeep.setAntiPeepMaskLayer(windowId)
它需要一个 windowId。这个参数很重要,下一篇会专门讲它从哪来。
什么时候拉起蒙层
在 handleAntiPeepStatus() 里,只有状态为 HIDE,并且开关打开时,才会尝试拉起蒙层:
case dlpAntiPeep.DlpAntiPeepStatus.HIDE:
if (this.isShowToggle && this.isToggleOpened) {
try {
if (!this.isSystemLayerTriggered && !this.isAlertDialogShow) {
const id = AppStorage.get(ConstValues.WINDOW_ID_NAME) as number;
this.isSystemLayerTriggered = await showSystemMaskLayer(id);
} else {
Logger.info(TAG, `Ignore HIDE status`);
}
} catch (err) {
Logger.error(TAG, `Show mask layer error:${JSON.stringify(err)}`);
}
}
this.summaryShow(false);
this.itemsEnableShow(false);
break;
这里有两个限制条件:
this.isShowToggle:当前 API 版本支持展示这个开关;this.isToggleOpened:用户确实打开了页面里的蒙层开关。
只有两个都满足,才会调用系统蒙层。
为什么要防止重复触发
代码里还有两个布尔值:
private isSystemLayerTriggered: boolean = false;
private isAlertDialogShow: boolean = false;
它们用来避免重复拉起蒙层和重复弹提示。状态监听可能多次收到 HIDE,如果每次都调用 setAntiPeepMaskLayer(),体验会很糟糕。
项目的处理是:第一次触发后记录 isSystemLayerTriggered,后续相同状态直接忽略。
这个细节很实用。做系统能力回调时,一定要考虑“重复事件”。
蒙层成功后还会弹提醒
如果蒙层成功触发,项目会延迟弹一个提示:
if (this.isSystemLayerTriggered) {
setTimeout(() => {
if (!this.isAlertDialogShow) {
this.isAlertDialogShow = true;
this.alertDialogController.open();
}
})
}
提示内容大意是:防窥蒙层已经触发过,后续再次进入页面前不会重复触发。
这对用户很重要。否则用户可能以为开关失效了。
局部脱敏和系统蒙层不是二选一
项目在调用蒙层后,仍然会执行:
this.summaryShow(false);
this.itemsEnableShow(false);
这点很关键。系统蒙层是增强保护,字段脱敏是基础保护。即使蒙层调用失败,页面上的敏感字段也应该隐藏。
所以真实项目里别把安全全部押在一个能力上,能做多层保护就做多层。
写在最后
系统防窥蒙层比自己写遮罩更可靠,因为它来自系统安全能力。但应用侧仍然要负责触发时机、重复控制和失败兜底。
下一篇我们拆 windowId。没有它,setAntiPeepMaskLayer() 根本不知道要保护哪个窗口。

1596

被折叠的 条评论
为什么被折叠?



