HarmonyOS7 系统防窥蒙层怎么拉起来:比自己写遮罩靠谱多了

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

项目地址:https://gitcode.com/HarmonyOS_Samples/AntiPeep

A hand-drawn doodle illustration on pure white pap

先看效果

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

系统防窥蒙层

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

折叠屏系统防窥蒙层

这不是应用自己写的半透明 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() 根本不知道要保护哪个窗口。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值