HarmonyOS 防窥保护实战进阶:金融场景完整接入与系统蒙层实践

前言

上一篇文章中,我们系统介绍了防窥保护(dlpAntiPeep)的概念原理、窥视状态体系和基础 API 用法。但概念终要落地——金融类应用如何实现敏感金额自动隐藏?系统级防窥蒙层如何拉起?实况窗提醒如何触发?权限如何申请与管理?

本文将以金融场景为切入点,深入拆解防窥保护的完整接入实战,包括工具类封装、系统蒙层控制、实况窗提醒、ACL 权限申请以及完整的金融账户页面代码实现。

一、金融场景需求分析

1.1 金融场景的隐私痛点

金融类应用汇集了大量的财务敏感信息,每一项都是不希望被他人知晓的隐私数据:

敏感信息类型具体内容泄露风险
账户资产账户余额、总资产数值暴露个人财务状况
收益明细收益曲线、收益金额暴露投资偏好和收益
持仓明细股票持仓、基金持仓暴露投资策略
交易记录转账记录、消费记录暴露消费习惯
银行卡号卡号、CVV 等金融欺诈风险

1.2 防窥保护响应策略

金融场景下,防窥保护提供三级响应策略:

级别策略触发条件用户体验
一级:字段隐藏敏感数字替换为 ****检测到窥视,立即触发轻量级,不影响页面浏览
二级:系统蒙层拉起系统级半透明蒙层窥视持续 + 用户开启蒙层开关中等级,遮盖整个窗口
三级:实况窗提醒屏幕顶部实况窗提示持续窥视风险提醒级,用户可感知风险

二、防窥保护工具类封装

2.1 工具类设计

封装一个完整的 AntiPeepUtils 工具类,统一管理能力检测、状态查询、监听注册和蒙层控制:

// entry/src/main/ets/utils/AntiPeepUtils.ets
import { dlpAntiPeep } from '@kit.DeviceSecurityKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { window } from '@kit.ArkUI';

const TAG = 'AntiPeepUtils';

/**
 * 防窥保护回调接口
 */
export interface AntiPeepCallback {
  onStatusChanged: (status: dlpAntiPeep.DlpAntiPeepStatus) => Promise<void>;
}

/**
 * 防窥保护工具类
 * 统一管理能力检测、状态查询、监听注册和蒙层控制
 */
export class AntiPeepUtils {
  /**
   * 检测设备是否支持防窥保护
   */
  static canUseAntiPeep(): boolean {
    return canIUse('SystemCapability.Security.DlpAntiPeep');
  }

  /**
   * 检查当前应用是否已开启防窥保护
   */
  static async isAntiPeepOn(): Promise<boolean> {
    try {
      if (AntiPeepUtils.canUseAntiPeep()) {
        const result = await dlpAntiPeep.isDlpAntiPeepSwitchOn();
        console.info(`${TAG} 防窥保护开关状态: ${result}`);
        return result;
      }
      return false;
    } catch (err) {
      const error = err as BusinessError;
      console.error(`${TAG} 检查开关状态失败: ${error.code}, ${error.message}`);
      return false;
    }
  }

  /**
   * 同步获取当前窥视状态
   */
  static getAntiPeepInfo(): dlpAntiPeep.DlpAntiPeepStatus | number {
    try {
      if (AntiPeepUtils.canUseAntiPeep()) {
        const status = dlpAntiPeep.getDlpAntiPeepInfo();
        console.info(`${TAG} 当前窥视状态: ${JSON.stringify(status)}`);
        return status;
      }
      return -1;
    } catch (err) {
      console.error(`${TAG} 获取窥视状态失败: ${JSON.stringify(err)}`);
      return -1;
    }
  }

  /**
   * 注册防窥保护状态监听
   */
  static listenOnAntiPeepStatus(antiPeepCB: AntiPeepCallback): boolean {
    try {
      if (AntiPeepUtils.canUseAntiPeep()) {
        console.info(`${TAG} 开始监听防窥保护状态`);

        dlpAntiPeep.on('dlpAntiPeep', (status: dlpAntiPeep.DlpAntiPeepStatus) => {
          console.info(`${TAG} 防窥状态变化: ${JSON.stringify(status)}`);
          if (antiPeepCB) {
            antiPeepCB.onStatusChanged(status);
          }
        });

        console.info(`${TAG} 防窥保护监听已注册`);
        return true;
      }
      return false;
    } catch (err) {
      const error = err as BusinessError;
      console.error(`${TAG} 注册监听失败: ${error.code}, ${error.message}`);
      return false;
    }
  }

  /**
   * 取消防窥保护状态监听
   */
  static listenOffAntiPeepStatus(): void {
    try {
      if (AntiPeepUtils.canUseAntiPeep()) {
        console.info(`${TAG} 取消防窥保护监听`);
        dlpAntiPeep.off('dlpAntiPeep');
        console.info(`${TAG} 防窥保护监听已取消`);
      }
    } catch (err) {
      const error = err as BusinessError;
      console.error(`${TAG} 取消监听失败: ${error.code}, ${error.message}`);
    }
  }

  /**
   * 拉起系统防窥蒙层
   * @param windowId 窗口 ID
   * @returns 是否成功拉起蒙层
   */
  static showSystemMaskLayer(windowId: number): Promise<boolean> {
    return new Promise((resolve) => {
      try {
        if (AntiPeepUtils.canUseAntiPeep()) {
          dlpAntiPeep.setAntiPeepMaskLayer(windowId)
            .then(() => {
              console.info(`${TAG} 系统防窥蒙层已拉起`);
              resolve(true);
            })
            .catch((err: BusinessError) => {
              console.error(`${TAG} 拉起蒙层失败: ${err.code}, ${err.message}`);
              resolve(false);
            });
        } else {
          resolve(false);
        }
      } catch (err) {
        console.error(`${TAG} 调用蒙层接口失败: ${JSON.stringify(err)}`);
        resolve(false);
      }
    });
  }

  /**
   * 修改窥视状态为 PASS
   * 直到手机锁屏或应用退出前一直返回非窥视状态
   */
  static passDlpAntiPeepInfo(): void {
    try {
      if (AntiPeepUtils.canUseAntiPeep()) {
        dlpAntiPeep.passDlpAntiPeepInfo();
        console.info(`${TAG} 窥视状态已修改为 PASS`);
      }
    } catch (err) {
      const error = err as BusinessError;
      console.error(`${TAG} 修改窥视状态失败: ${error.code}, ${error.message}`);
    }
  }

  /**
   * 拉起系统设置弹窗(API 23+)
   */
  static async requestAntiPeepOptions(context: Context): Promise<boolean> {
    try {
      if (AntiPeepUtils.canUseAntiPeep()) {
        const result = await dlpAntiPeep.requestAntiPeepOptions(context);
        console.info(`${TAG} 设置弹窗结果: ${JSON.stringify(result)}`);
        return true;
      }
      return false;
    } catch (err) {
      const error = err as BusinessError;
      console.error(`${TAG} 拉起设置弹窗失败: ${error.code}, ${error.message}`);
      return false;
    }
  }

  /**
   * 发布实况窗提醒(API 23+)
   */
  static async publishAntiPeepWarning(): Promise<boolean> {
    try {
      if (AntiPeepUtils.canUseAntiPeep()) {
        await dlpAntiPeep.publishAntiPeepInformation();
        console.info(`${TAG} 实况窗提醒已发布`);
        return true;
      }
      return false;
    } catch (err) {
      const error = err as BusinessError;
      console.error(`${TAG} 发布实况窗提醒失败: ${error.code}, ${error.message}`);
      return false;
    }
  }
}

三、系统防窥蒙层详解

3.1 蒙层机制

setAntiPeepMaskLayer() 是防窥保护最核心的防护手段。它拉起一个系统级半透明蒙层覆盖整个应用窗口,使窥视者无法看清屏幕内容。

特性说明
覆盖范围整个应用窗口
蒙层样式系统统一样式,半透明遮罩
触发时机检测到窥视时由应用主动调用
触发频率每次进入页面只触发一次
解除时机用户重新进入页面后自动解除

3.2 蒙层控制策略

/**
 * 系统防窥蒙层管理器
 * 控制蒙层触发时机和频率
 */
export class AntiPeepMaskLayerManager {
  private isSystemLayerTriggered: boolean = false;
  private isAlertDialogShow: boolean = false;
  private windowId: number = 0;

  constructor(windowId: number) {
    this.windowId = windowId;
  }

  /**
   * 尝试拉起系统蒙层
   * 每次进入页面只触发一次
   */
  async tryShowMaskLayer(): Promise<boolean> {
    // 蒙层已触发过,不再重复触发
    if (this.isSystemLayerTriggered) {
      console.info('系统蒙层已触发过,跳过');
      return false;
    }

    // 有弹窗正在显示,不触发蒙层
    if (this.isAlertDialogShow) {
      console.info('有弹窗正在显示,暂不触发蒙层');
      return false;
    }

    const result = await AntiPeepUtils.showSystemMaskLayer(this.windowId);
    if (result) {
      this.isSystemLayerTriggered = true;
    }
    return result;
  }

  /**
   * 重置蒙层状态(页面重新进入时调用)
   */
  reset(): void {
    this.isSystemLayerTriggered = false;
  }

  /**
   * 设置弹窗显示状态
   */
  setAlertDialogVisible(visible: boolean): void {
    this.isAlertDialogShow = visible;
  }
}

四、金融账户页面完整实战

4.1 场景描述

构建一个金融账户页面,包含以下功能:

  1. 账户总资产展示(敏感数字)
  2. 收益明细列表(敏感数字)
  3. 持仓明细(敏感信息)
  4. 检测到窥视时自动隐藏敏感数字
  5. 用户可选开启系统蒙层

4.2 完整实现代码

在这里插入图片描述

图:金融账户防窥保护——正常显示(左)与检测到窥视后隐藏敏感数字(右)对比

// entry/src/main/ets/pages/FinanceAccountPage.ets
import { dlpAntiPeep } from '@kit.DeviceSecurityKit';
import { AntiPeepUtils, AntiPeepCallback } from '../utils/AntiPeepUtils';
import { AntiPeepMaskLayerManager } from '../utils/AntiPeepMaskLayerManager';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';

// 账户数据接口
interface AccountData {
  totalAssets: string;
  dailyReturn: string;
  totalReturn: string;
  holdings: HoldingItem[];
}

interface HoldingItem {
  name: string;
  code: string;
  amount: string;
  returnRate: string;
}

@Entry
@Component
struct FinanceAccountPage {
  @State private isAntiPeepSupported: boolean = false;
  @State private isSwitchOn: boolean = false;
  @State private isPeeping: boolean = false;
  @State private isToggleOpened: boolean = false;
  @State private isSystemLayerTriggered: boolean = false;

  // 真实数据
  private realData: AccountData = {
    totalAssets: '¥128,456.78',
    dailyReturn: '+¥2,345.67',
    totalReturn: '+¥18,456.78',
    holdings: [
      { name: '招商银行', code: '600036', amount: '¥45,678.00', returnRate: '+12.5%' },
      { name: '贵州茅台', code: '600519', amount: '¥82,778.78', returnRate: '+8.3%' },
    ]
  };

  // 显示数据(窥视时隐藏)
  @State private displayData: AccountData = {
    totalAssets: '¥128,456.78',
    dailyReturn: '+¥2,345.67',
    totalReturn: '+¥18,456.78',
    holdings: []
  };

  private maskLayerManager: AntiPeepMaskLayerManager = new AntiPeepMaskLayerManager(0);

  private antiPeepCB: AntiPeepCallback = {
    onStatusChanged: async (status: dlpAntiPeep.DlpAntiPeepStatus) => {
      await this.handleAntiPeepStatus(status);
    }
  };

  aboutToAppear(): void {
    this.initializeAntiPeep();
  }

  aboutToDisappear(): void {
    AntiPeepUtils.listenOffAntiPeepStatus();
  }

  /**
   * 初始化防窥保护
   */
  private async initializeAntiPeep(): Promise<void> {
    this.isAntiPeepSupported = AntiPeepUtils.canUseAntiPeep();
    if (!this.isAntiPeepSupported) {
      return;
    }

    this.isSwitchOn = await AntiPeepUtils.isAntiPeepOn();
    if (!this.isSwitchOn) {
      return;
    }

    // 获取窗口 ID
    try {
      const mainWindow = await window.getLastWindow(getContext(this));
      const windowProperties = mainWindow.getWindowProperties();
      this.maskLayerManager = new AntiPeepMaskLayerManager(windowProperties.id);
    } catch (err) {
      console.error(`获取窗口 ID 失败: ${JSON.stringify(err)}`);
    }

    // 获取初始状态
    const initialStatus = AntiPeepUtils.getAntiPeepInfo();
    if (typeof initialStatus === 'number' && initialStatus !== -1) {
      await this.handleAntiPeepStatus(initialStatus as dlpAntiPeep.DlpAntiPeepStatus);
    }

    // 注册实时监听
    AntiPeepUtils.listenOnAntiPeepStatus(this.antiPeepCB);
  }

  /**
   * 处理防窥保护状态变化
   */
  private async handleAntiPeepStatus(status: dlpAntiPeep.DlpAntiPeepStatus): Promise<void> {
    switch (status) {
      case dlpAntiPeep.DlpAntiPeepStatus.PASS:
        this.isPeeping = false;
        this.displayData = this.realData;
        break;

      case dlpAntiPeep.DlpAntiPeepStatus.HIDE:
        this.isPeeping = true;
        // 隐藏敏感数字
        this.displayData = {
          totalAssets: '****',
          dailyReturn: '****',
          totalReturn: '****',
          holdings: this.realData.holdings.map(h => ({
            ...h,
            amount: '****',
            returnRate: '****'
          }))
        };

        // 如果用户开启了蒙层开关,且蒙层尚未触发
        if (this.isToggleOpened && !this.isSystemLayerTriggered) {
          const success = await this.maskLayerManager.tryShowMaskLayer();
          if (success) {
            this.isSystemLayerTriggered = true;
          }
        }
        break;

      default:
        this.displayData = this.realData;
        break;
    }
  }

  @Builder
  buildHeader() {
    Column() {
      Text('我的资产')
        .fontSize(16)
        .fontColor('#999')
        .margin({ bottom: 8 })

      Text(this.displayData.totalAssets)
        .fontSize(36)
        .fontWeight(FontWeight.Bold)
        .fontColor(this.isPeeping ? '#CCC' : '#333')
        .animation({ duration: 300 })

      if (this.isPeeping) {
        Row() {
          SymbolGlyph($r('sys.symbol.eye'))
            .fontSize(14)
            .fontColor(['#FF3B30'])
          Text('检测到他人窥视,敏感信息已隐藏')
            .fontSize(13)
            .fontColor('#FF3B30')
            .margin({ left: 4 })
        }
        .margin({ top: 8 })
      }
    }
    .width('100%')
    .padding(24)
    .borderRadius(16)
    .backgroundColor('#FFF')
    .shadow({ radius: 8, color: 'rgba(0,0,0,0.06)', offsetY: 2 })
    .margin({ left: 16, right: 16, top: 16 })
  }

  @Builder
  buildReturnCard() {
    Row({ space: 24 }) {
      Column() {
        Text('今日收益')
          .fontSize(13)
          .fontColor('#999')
        Text(this.displayData.dailyReturn)
          .fontSize(20)
          .fontWeight(FontWeight.Medium)
          .fontColor(this.isPeeping ? '#CCC' : '#34C759')
          .margin({ top: 4 })
      }
      .layoutWeight(1)

      Divider()
        .vertical(true)
        .strokeWidth(0.5)
        .color('#E5E5E5')
        .height(40)

      Column() {
        Text('累计收益')
          .fontSize(13)
          .fontColor('#999')
        Text(this.displayData.totalReturn)
          .fontSize(20)
          .fontWeight(FontWeight.Medium)
          .fontColor(this.isPeeping ? '#CCC' : '#34C759')
          .margin({ top: 4 })
      }
      .layoutWeight(1)
    }
    .width('100%')
    .padding(20)
    .borderRadius(16)
    .backgroundColor('#FFF')
    .shadow({ radius: 8, color: 'rgba(0,0,0,0.06)', offsetY: 2 })
    .margin({ left: 16, right: 16, top: 12 })
  }

  @Builder
  buildHoldingItem(item: HoldingItem, index: number) {
    Row() {
      Column() {
        Text(item.name)
          .fontSize(16)
          .fontWeight(FontWeight.Medium)
          .fontColor('#333')
        Text(item.code)
          .fontSize(12)
          .fontColor('#999')
          .margin({ top: 4 })
      }
      .alignItems(HorizontalAlign.Start)
      .layoutWeight(1)

      Column() {
        Text(item.amount)
          .fontSize(16)
          .fontWeight(FontWeight.Medium)
          .fontColor(this.isPeeping ? '#CCC' : '#333')
        Text(item.returnRate)
          .fontSize(12)
          .fontColor(this.isPeeping ? '#CCC' : '#34C759')
          .margin({ top: 4 })
      }
      .alignItems(HorizontalAlign.End)
    }
    .width('100%')
    .padding({ left: 20, right: 20, top: 14, bottom: 14 })
  }

  @Builder
  buildHoldingList() {
    Column() {
      Text('持仓明细')
        .fontSize(16)
        .fontWeight(FontWeight.Bold)
        .fontColor('#333')
        .width('100%')
        .padding({ left: 20, top: 16, bottom: 8 })

      ForEach(this.displayData.holdings, (item: HoldingItem, index: number) => {
        this.buildHoldingItem(item, index)
        if (index < this.displayData.holdings.length - 1) {
          Divider()
            .strokeWidth(0.5)
            .color('#F0F0F0')
            .margin({ left: 20, right: 20 })
        }
      })
    }
    .width('100%')
    .borderRadius(16)
    .backgroundColor('#FFF')
    .shadow({ radius: 8, color: 'rgba(0,0,0,0.06)', offsetY: 2 })
    .margin({ left: 16, right: 16, top: 12, bottom: 16 })
  }

  @Builder
  buildAntiPeepToggle() {
    Row() {
      Text('开启系统防窥蒙层')
        .fontSize(14)
        .fontColor('#333')
      Blank()
      Toggle({ type: ToggleType.Switch, isOn: this.isToggleOpened })
        .onChange((isOn: boolean) => {
          this.isToggleOpened = isOn;
        })
    }
    .width('100%')
    .padding(16)
    .borderRadius(12)
    .backgroundColor('#FFF')
    .margin({ left: 16, right: 16, bottom: 16 })
  }

  @Builder
  buildGuideButton() {
    if (!this.isSwitchOn && this.isAntiPeepSupported) {
      Button('开启防窥保护')
        .fontSize(16)
        .fontColor(Color.White)
        .backgroundColor('#007AFF')
        .borderRadius(12)
        .width('90%')
        .height(48)
        .margin({ bottom: 16 })
        .onClick(async () => {
          await AntiPeepUtils.requestAntiPeepOptions(getContext(this));
          this.isSwitchOn = await AntiPeepUtils.isAntiPeepOn();
          if (this.isSwitchOn) {
            this.initializeAntiPeep();
          }
        })
    }
  }

  build() {
    Column() {
      Scroll() {
        Column() {
          this.buildHeader()
          this.buildReturnCard()
          this.buildHoldingList()
          this.buildAntiPeepToggle()
          this.buildGuideButton()
        }
        .width('100%')
      }
      .width('100%')
      .layoutWeight(1)
      .scrollBar(BarState.Off)
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#F5F6F8')
  }
}

五、实况窗提醒机制

5.1 实况窗提醒原理

当设备持续处于窥屏风险状态时,系统会通过实况窗(Live Window)在屏幕顶部向用户发出提醒。系统只会主动发送一次时长 5 秒的提醒,再次提醒需要通过 publishAntiPeepInformation() 接口主动触发。

5.2 实况窗提醒实现

/**
 * 防窥保护实况窗提醒管理器
 */
export class AntiPeepLiveWindowManager {
  private lastPublishTime: number = 0;
  private readonly PUBLISH_INTERVAL_MS: number = 30000; // 30秒间隔

  /**
   * 尝试发布实况窗提醒
   * 控制发布频率,避免频繁打扰用户
   */
  async tryPublishWarning(): Promise<boolean> {
    const now = Date.now();

    // 距离上次发布不足 30 秒,跳过
    if (now - this.lastPublishTime < this.PUBLISH_INTERVAL_MS) {
      console.info('实况窗提醒间隔不足,跳过');
      return false;
    }

    const result = await AntiPeepUtils.publishAntiPeepWarning();
    if (result) {
      this.lastPublishTime = now;
    }
    return result;
  }

  /**
   * 重置提醒计时器
   */
  reset(): void {
    this.lastPublishTime = 0;
  }
}

5.3 与蒙层协同使用

/**
 * 防窥保护综合响应策略
 * 结合蒙层和实况窗提醒
 */
private async handleAntiPeepStatusWithLiveWindow(
  status: dlpAntiPeep.DlpAntiPeepStatus
): Promise<void> {
  switch (status) {
    case dlpAntiPeep.DlpAntiPeepStatus.HIDE:
      // 1. 隐藏敏感信息
      this.hideSensitiveData();

      // 2. 尝试拉起系统蒙层
      if (this.isToggleOpened) {
        await this.maskLayerManager.tryShowMaskLayer();
      }

      // 3. 尝试发布实况窗提醒
      await this.liveWindowManager.tryPublishWarning();
      break;

    case dlpAntiPeep.DlpAntiPeepStatus.PASS:
      // 恢复正常显示
      this.showSensitiveData();
      break;
  }
}

六、权限申请与管理

6.1 ACL 权限申请流程

防窥保护需要 ohos.permission.DLP_GET_HIDE_STATUS 权限,这是一个受限权限(ACL),申请流程如下:

  1. module.json5 中声明权限
  2. 本地调试时使用自动签名
  3. 应用上架时在 AGC 平台 申请 ACL 权限

6.2 module.json5 配置

{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.DLP_GET_HIDE_STATUS",
        "reason": "$string:antipeep_reason",
        "usedScene": {
          "abilities": ["FinanceAccountAbility"],
          "when": "inuse"
        }
      }
    ]
  }
}

6.3 权限说明文案

resources/base/element/string.json 中声明权限说明:

{
  "string": [
    {
      "name": "antipeep_reason",
      "value": "防窥保护需要检测屏幕窥视状态,以保护您的账户余额、持仓明细等敏感信息不被他人窥视"
    }
  ]
}

七、完整生命周期管理

7.1 生命周期状态机

防窥保护在实际项目中的完整生命周期管理:

/**
 * 防窥保护生命周期状态机
 */
export class AntiPeepLifecycle {
  private static instance: AntiPeepLifecycle | null = null;
  private isInitialized: boolean = false;
  private isListening: boolean = false;
  private isPageVisible: boolean = false;

  static getInstance(): AntiPeepLifecycle {
    if (!AntiPeepLifecycle.instance) {
      AntiPeepLifecycle.instance = new AntiPeepLifecycle();
    }
    return AntiPeepLifecycle.instance;
  }

  /**
   * 页面可见时初始化
   */
  async onPageShow(): Promise<void> {
    this.isPageVisible = true;

    if (!this.isInitialized) {
      const supported = AntiPeepUtils.canUseAntiPeep();
      if (!supported) return;

      const switchOn = await AntiPeepUtils.isAntiPeepOn();
      if (!switchOn) return;

      this.isInitialized = true;
    }

    if (!this.isListening) {
      this.startListening();
    }
  }

  /**
   * 页面不可见时暂停监听
   */
  onPageHide(): void {
    this.isPageVisible = false;
  }

  /**
   * 页面销毁时清理
   */
  onPageDestroy(): void {
    this.stopListening();
    this.isInitialized = false;
    AntiPeepLifecycle.instance = null;
  }

  private startListening(): void {
    // 注册监听
    this.isListening = true;
  }

  private stopListening(): void {
    AntiPeepUtils.listenOffAntiPeepStatus();
    this.isListening = false;
  }
}

八、常见问题与排错

8.1 常见问题

问题可能原因解决方案
监听不触发未开启人脸识别或防窥保护开关按前置条件逐一检查
开关检测返回 false用户未在系统设置中开启调用 requestAntiPeepOptions 引导用户
蒙层拉起失败窗口 ID 不正确或蒙层已触发检查窗口 ID,确认蒙层每次进入页面只触发一次
权限被拒绝(201)未申请 ACL 权限本地调试用自动签名,上架需申请 ACL
能力不支持(801)设备不支持使用 canIUse 前置检测,不支持时降级
模拟器无法测试模拟器不支持必须使用带人脸识别的真机

8.2 调试检查清单

/**
 * 防窥保护调试诊断工具
 */
export class AntiPeepDiagnostics {
  static async runDiagnostics(): Promise<DiagnosticsResult> {
    const result: DiagnosticsResult = {
      deviceSupported: false,
      switchOn: false,
      hasPermission: false,
      canListen: false,
      issues: []
    };

    // 1. 检测设备能力
    result.deviceSupported = canIUse('SystemCapability.Security.DlpAntiPeep');
    if (!result.deviceSupported) {
      result.issues.push('当前设备不支持防窥保护能力');
      return result;
    }

    // 2. 检测开关状态
    result.switchOn = await AntiPeepUtils.isAntiPeepOn();
    if (!result.switchOn) {
      result.issues.push('防窥保护开关未开启,请在 设置 > 隐私与安全 > 防窥保护 中开启');
    }

    // 3. 检测权限
    try {
      const status = dlpAntiPeep.getDlpAntiPeepInfo();
      result.hasPermission = true;
    } catch (err) {
      result.issues.push('权限不足,请检查 ohos.permission.DLP_GET_HIDE_STATUS 权限');
    }

    result.canListen = result.deviceSupported && result.switchOn && result.hasPermission;

    return result;
  }
}

interface DiagnosticsResult {
  deviceSupported: boolean;
  switchOn: boolean;
  hasPermission: boolean;
  canListen: boolean;
  issues: string[];
}

九、总结

本文从金融场景实战角度深入讲解了防窥保护的进阶应用:

  • 工具类封装AntiPeepUtils 统一管理能力检测、状态查询、监听注册和蒙层控制
  • 系统蒙层setAntiPeepMaskLayer 拉起系统级半透明蒙层,每次进入页面只触发一次
  • 金融场景完整实战:账户总资产、收益明细、持仓明细的敏感信息隐藏与恢复
  • 实况窗提醒publishAntiPeepInformation 发布系统级提醒,控制发布频率
  • 权限管理:ACL 权限申请流程,module.json5 配置与权限说明文案
  • 生命周期管理:页面可见性控制、防窥保护初始化/销毁的完整状态机

防窥保护是 HarmonyOS 安全体系从"系统内部"延伸到"物理空间"的重要里程碑。掌握这些实战技巧,你的应用将为用户提供真正的隐私安全保障。

下一篇将深入讲解即时通讯、短视频等多场景适配,以及与 DLP 数据防泄漏框架的联动实践。

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

Logo

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

更多推荐