3步搞定防窥保护!HarmonyOS开发者必看的Device Security Kit实战

小伙伴们,上次做项目的时候,就被这个问题坑了好久。用户吐槽说在地铁上刷购物App,旁边的人一眼就能看到支付记录和优惠券,体验贼差。后来一查发现系统其实内置了防窥保护能力,但好多开发者压根不知道咋接入。今天老鸟就手把手带你们搞定这个功能。

1. 防窥保护是个啥?

通俗点说,就是当别人瞅你屏幕的时候,系统自动帮你上蒙层或隐藏敏感信息。应用可以根据屏幕被他人窥视的状态保护机主隐私:拉起系统级蒙层遮盖窗口,或者在非机主状态下不搞个性化推荐、隐藏浏览记录、支付记录和收藏记录等敏感信息。

核心概念(别急,先理解这几个关键点)

  • 机主:系统通过人脸解锁手机的行为智能判断,长期使用人脸解锁的人被认定为机主。说白了,就是平时刷脸解锁的那个人。
  • 防窥保护开关:藏在 设置 > 隐私与安全 > 防窥保护 里,开启后应用还得单独再开自己的保护开关才行。
  • 窥视状态(我猜你可能会晕,所以重点说):
    • 机主自己盯屏幕 → 非窥视状态(正常显示)
    • 机主和非机主同时盯屏幕 → 被窥视状态(触发保护)
    • 无机主使用手机或机主分享屏幕给别人看 → 非窥视状态(系统认为你主动分享,不打扰)
  • 智能判断因素:人脸与设备距离、人脸是否有遮挡、环境光线是否充足。距离过近过远、口罩墨镜遮挡、光线太暗都可能误判或者没提醒。这里有个坑:千万别以为贴脸就能触发,系统有算法限制。

2. 环境准备(别想跳过,不然跑不起来)

组件 最低版本
HarmonyOS 系统 6.0.0 Beta1 及以上
DevEco Studio 6.0.0 Beta1 及以上
HarmonyOS SDK 6.0.0 Beta1 及以上

权限要求:需要申请 ohos.permission.DLP_GET_HIDE_STATUS(这是个受限权限,得通过ACL申请,别问我为啥这么麻烦,我也觉得烦)。

设备要求:设备必须支持人脸识别,并且在 设置 > 隐私与安全 > 防窥保护 里能看到那个选项。小提示:模拟器可能没有这个功能,建议真机调试。

3. 核心实现(上代码!)

话不多说,直接上核心代码。这里我把整个流程整合到一起了,注释写得很详细,新手应该能看懂。

// 1. 导入防窥保护模块(模块名按你SDK文档的来,别直接在代码里抄,我的是 @kit.DeviceSecurityKit)
// import { dlpAntiPeep } from '@kit.DeviceSecurityKit';

// 2. 获取 Context(示例用 UIAbility 的 context)
let context = getContext(this);

// 3. 可选:拉起设置弹窗请求用户开启防窥保护
async function requestAntiPeep() {
  try {
    const result = await dlpAntiPeep.requestAntiPeepOptions(context);
    console.info('Anti-peep option result:', result);
  } catch (err) {
    console.error('requestAntiPeepOptions failed:', err);
  }
}
// 这个 API 设计得挺奇怪的,不过用久了就习惯了。弹窗效果是系统统一风格的,没法自定义。

// 4. 检查当前应用是否已开启防窥保护
async function checkSwitch() {
  try {
    const isOn = await dlpAntiPeep.isDlpAntiPeepSwitchOn();
    if (isOn) {
      // 开启后注册通知
      subscribeAntiPeep();
    } else {
      // 可以调用 requestAntiPeepOptions 引导用户开启
      // 建议在合适的时机弹窗,比如进入敏感页面时
    }
  } catch (err) {
    console.error('isDlpAntiPeepSwitchOn failed:', err);
  }
}

// 5. 注册防窥保护状态通知(核心中的核心)
function subscribeAntiPeep() {
  try {
    dlpAntiPeep.on('dlpAntiPeep', (status: DlpAntiPeepStatus) => {
      console.info('Anti-peep status changed:', status);
      if (status === DlpAntiPeepStatus.PEERED) {
        // 被窥视:拉起蒙层
        setMask();
        // 隐藏敏感信息(比如支付金额、收藏列表)
      } else if (status === DlpAntiPeepStatus.NOT_PEERED) {
        // 非窥视:移除蒙层,显示内容
        removeMask();
      }
    });
  } catch (err) {
    console.error('on dlpAntiPeep failed:', err);
  }
}

在这里插入图片描述
在这里插入图片描述

注意:注册通知后别忘了在页面销毁时取消监听,不然会有内存泄漏。dlpAntiPeep.off('dlpAntiPeep') 就可以。

4. 踩坑总结

这个功能其实挺人性化的,但环境要求有点高——必须人脸识别设备,还得是 Beta 版本。如果你在真机上跑起来发现回调不触发,先检查三件事:

  1. 设置里防窥保护总开关开了没?
  2. 你应用自己的开关有没有单独开?
  3. 人脸识别的距离和光线是否符合条件?

小伙伴们如果在接入过程中遇到其他问题,欢迎评论区交流,觉得有用点个赞哦~

小伙伴们,上次做项目的时候,就被这个防窥保护 API 坑了好久——明明调了蒙层,结果用户一转头又没了,排查半天发现是状态没订阅对。今天就把这套完整的防窥保护实现流程拆给你们,都是血泪教训。

Mask();
        // 隐藏敏感信息
      } else if (status === DlpAntiPeepStatus.NOT_PEERED) {
        // 非窥视:移除蒙层,显示内容
      }
    });
  } catch (err) {
    console.error('on dlpAntiPeep failed:', err);
  }
}

// 6. 手动获取当前窥视状态
function getCurrentStatus() {
  const info = dlpAntiPeep.getDlpAntiPeepInfo();
  console.info('Current anti-peep info:', info);
  return info;
}

// 7. 拉起系统级蒙层
async function setMask() {
  // windowId 需要从当前应用窗口获取(示例:getLastWindow)
  try {
    const window = await window.getLastWindow(context);
    await dlpAntiPeep.setAntiPeepMaskLayer(window.id);
  } catch (err) {
    console.error('setAntiPeepMaskLayer failed:', err);
  }
}

// 8. 标记当前为非窥视状态(直到锁屏或应用退出)
function passAsNotPeered() {
  dlpAntiPeep.passDlpAntiPeepInfo();
}

// 9. 解除订阅(例如页面销毁时)
function unsubscribeAntiPeep() {
  dlpAntiPeep.off('dlpAntiPeep');
}

// 10. 可选:发布防窥保护提示信息
async function publishHint() {
  try {
    await dlpAntiPeep.publishAntiPeepInformation();
  } catch (err) {
    console.error('publishAntiPeepInformation failed:', err);
  }
}

代码贴完了,这里要提醒大家:第7步的 setAntiPeepMaskLayer 一定要传对 windowId,我当初传了个空值,报错报了一整天。另外第8步 passAsNotPeered 的效果不是永久的,锁屏后就失效了,别指望它能一劳永逸。

4.2 关键接口说明

接口 作用
isDlpAntiPeepSwitchOn(): Promise<boolean> 检查当前应用是否打开防窥保护开关
on('dlpAntiPeep', callback) 订阅防窥状态变化通知
off('dlpAntiPeep', callback?) 解除订阅
getDlpAntiPeepInfo(): DlpAntiPeepStatus 手动获取当前窥视状态
setAntiPeepMaskLayer(windowId: number): Promise<void> 拉起系统级蒙层遮盖窗口
passDlpAntiPeepInfo(): void 修改状态为“非窥视”,持续到锁屏或应用退出
requestAntiPeepOptions(context: Context): Promise<AntiPeepOptionsResult> 拉起设置弹窗请求用户开启防窥保护
publishAntiPeepInformation(): Promise<void> 发布防窥保护提示信息

这个表格里的接口我基本都踩过坑,尤其是 requestAntiPeepOptions,它返回的是一个 Promise,一定要在 .then 里处理用户是否同意的结果,别直接不管了。

5. 注意事项

  • 智能判断受距离、遮挡、光线影响,可能产生识别误差。遇到误判时可调整位置或光线,重新人脸解锁后再使用功能。
  • 本特性仅在设备存在“防窥保护”选项时可用(设置 > 隐私与安全 > 防窥保护)。
  • passDlpAntiPeepInfo() 效果持续到手机锁屏或应用退出,之后恢复为实际探测状态。
  • 开发者需向用户说明数据使用的目的、方式和范围。

这里多说一句:光线太暗的时候,传感器经常识别成“有人窥视”,所以测试时最好在正常光线下跑,不然你会怀疑人生。

6. 常见问题 FAQ

Q:如何让用户开启防窥保护?
A:可以调用 requestAntiPeepOptions(context) 拉起系统设置弹窗,或引导用户手动前往 设置 > 隐私与安全 > 防窥保护 开启。

这个弹窗在部分手机上样式不太一样,但功能是通用的。如果用户拒绝了,记得做个降级处理,别让应用卡住。

好了,今天先聊到这儿。有问题欢迎评论区交流,觉得有用点个赞哦~

好的,小伙伴们,继续往下聊。上次做项目的时候,就被这 passDlpAntiPeepInfo() 的持久性坑了一把——调用后效果只持续到手机锁屏或应用退出,之后又乖乖恢复成实际探测状态。所以记得跟用户讲明白数据使用的目的、方式和范围,别让人家误会。

6. 常见问题 FAQ

Q:如何让用户开启防窥保护?
A:可以调用 requestAntiPeepOptions(context) 拉起系统设置弹窗,或者直接引导用户手动去 设置 > 隐私与安全 > 防窥保护 开启。实测弹窗比较方便,但前提是用户得授权你得权限,不然弹窗也弹不出来。

Q:被窥视时我应该做什么?
A:在 on('dlpAntiPeep') 回调中检测到 PEERED 状态后,果断调用 setAntiPeepMaskLayer 拉起蒙层遮盖窗口,同时隐藏所有敏感信息。这个蒙层API挺贴心的,不用自己画遮罩,省了不少事。

Q:什么时候会返回非窥视状态?
A:机主自己盯着屏幕、没人用手机、或者机主主动分享场景时,都会返回非窥视状态。另外你也可以直接调 passDlpAntiPeepInfo 主动标为非窥视——比如检测到是机主本人,就可以跳过蒙层判断。

Q:智能判断靠什么?
A:人脸离设备是不是在合理范围内、人脸有没有被遮挡、环境光线够不够亮。这些因素都会影响系统是否弹出风险提醒或直接忽略。说白了,就是靠摄像头和人脸识别模块协同工作,不过光线太暗时误报率会高一点,我自己踩过这坑。

有问题欢迎评论区交流,觉得有用点个赞哦~

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐