鸿蒙学习实战之路-STG系列(9/11)-应用访问限制-设置限制

朋友们,前几篇我们学习了守护策略的管理功能。今天这篇我们来学习应用访问限制的设置功能 - 这就像是给你的应用设置一个"准入名单"或"禁止名单" o(╯□╰)o

应用访问限制功能可以让你限制用户访问某些应用,或者只允许用户访问某些应用。这就像给孩子设置一个"白名单"或"黑名单",非常实用~

今天这篇,我会手把手带你实现应用访问限制的设置功能,全程不超过5分钟(不含你测试的时间)~


一、应用访问限制概述

应用访问限制功能可以让你对指定的应用进行访问限制,有两种限制类型:

1. 限制类型

限制类型 说明 使用场景
禁止清单(BLOCKLIST_TYPE) 对禁止清单里的应用做限制 不让孩子访问某些应用(如游戏、社交)
允许清单(ALLOWLIST_TYPE) 对允许清单以外的应用做限制 只允许孩子访问某些应用(如学习类应用)

2. 业务流程

应用调用设置应用访问限制接口
    ↓
系统检查应用是否有权限、用户是否授权
    ↓
如果没有权限 → 抛出错误码
如果有权限 → 解析参数
    ↓
根据限制类型和应用 Token 列表
    ↓
对应用进行限制处理
    ↓
返回处理结果

二、核心接口

设置应用访问限制的核心接口:

接口名 说明
setAppsRestriction(appInfo, restrictionType) 根据应用 token 数组和限制类型,设置应用访问限制

接口参数说明

  • appInfo: 应用信息对象,包含 appTokens 数组
  • restrictionType: 限制类型,可以是 BLOCKLIST_TYPEALLOWLIST_TYPE

边界场景

🥦 西兰花小贴士:

  1. 空列表 + 禁止清单: 如果传入的应用列表为空,限制类型为禁止清单,则不对任何应用做限制(相当于没有开启有效管控)

  2. 空列表 + 允许清单: 如果传入的应用列表为空,限制类型为允许清单,则对除了系统内置允许清单应用(如时钟、电话等)、管控发起应用本身、已授权的管控应用和健康使用设备之外的所有应用做限制

  3. 重复调用: 对同一个管控应用,如果反复调用该接口做限制(不管是允许清单还是禁用清单),均以最新的一次的限制来生效


三、开发步骤

步骤 1: 导入相关模块

import { guardService, appPicker } from '@kit.ScreenTimeGuardKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';

步骤 2: 实现应用访问限制设置功能

@Entry
@Component
struct SetAppsRestrictionDemo {
  @State selectedTokens: string[] = [];
  @State restrictionType: string = 'BLOCKLIST_TYPE';
  @State message: string = '';

  /**
   * 选择要限制的应用
   */
  async selectApps() {
    try {
      const tokens = await appPicker.startAppPicker(
        this.getUIContext().getHostContext() as common.UIAbilityContext,
        { appTokens: this.selectedTokens }
      );
      this.selectedTokens = tokens;
      this.message = `已选择 ${tokens.length} 个应用`;
      hilog.info(0x0000, 'SetAppsRestrictionDemo', 
        `selected ${tokens.length} apps`);
    } catch (err) {
      const message = (err as BusinessError).message;
      const code = (err as BusinessError).code;
      this.message = `选择应用失败: ${message}`;
      hilog.error(0x0000, 'SetAppsRestrictionDemo',
        `startAppPicker failed with error code: ${code}, message: ${message}`);
    }
  }

  /**
   * 设置应用访问限制
   */
  async setRestriction() {
    if (this.selectedTokens.length === 0) {
      this.message = '请先选择要限制的应用';
      return;
    }

    try {
      const appInfo: guardService.AppInfo = {
        appTokens: this.selectedTokens
      };

      const restrictionType: guardService.RestrictionType = 
        this.restrictionType === 'BLOCKLIST_TYPE' 
          ? guardService.RestrictionType.BLOCKLIST_TYPE 
          : guardService.RestrictionType.ALLOWLIST_TYPE;

      await guardService.setAppsRestriction(appInfo, restrictionType);
      this.message = `应用访问限制设置成功 (${this.getRestrictionTypeDesc()})`;
      hilog.info(0x0000, 'SetAppsRestrictionDemo', 
        `setAppsRestriction succeeded with type: ${this.restrictionType}`);
    } catch (err) {
      const message = (err as BusinessError).message;
      const code = (err as BusinessError).code;
      this.message = `设置失败: ${message}`;
      hilog.error(0x0000, 'SetAppsRestrictionDemo',
        `setAppsRestriction failed with error code: ${code}, message: ${message}`);
    }
  }

  /**
   * 获取限制类型描述
   */
  getRestrictionTypeDesc(): string {
    return this.restrictionType === 'BLOCKLIST_TYPE' ? '禁止清单' : '允许清单';
  }

  build() {
    Column() {
      Text('应用访问限制设置演示')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 40 })

      Text(this.message)
        .fontSize(14)
        .margin({ top: 20 })
        .fontColor('#666666')

      // 限制类型选择
      Text('限制类型')
        .fontSize(16)
        .margin({ top: 30 })

      Row() {
        Button('禁止清单')
          .onClick(() => { this.restrictionType = 'BLOCKLIST_TYPE'; })
          .backgroundColor(this.restrictionType === 'BLOCKLIST_TYPE' ? '#007DFF' : '#F5F5F5')
          .fontColor(this.restrictionType === 'BLOCKLIST_TYPE' ? '#FFFFFF' : '#000000')
          .margin({ right: 10 })

        Button('允许清单')
          .onClick(() => { this.restrictionType = 'ALLOWLIST_TYPE'; })
          .backgroundColor(this.restrictionType === 'ALLOWLIST_TYPE' ? '#007DFF' : '#F5F5F5')
          .fontColor(this.restrictionType === 'ALLOWLIST_TYPE' ? '#FFFFFF' : '#000000')
          .margin({ left: 10 })
      }
      .margin({ top: 10 })
      .width('80%')

      // 限制类型说明
      Text(this.getRestrictionTypeDesc() + ': ' + 
        (this.restrictionType === 'BLOCKLIST_TYPE' 
          ? '禁止访问选中的应用' 
          : '只允许访问选中的应用'))
        .fontSize(14)
        .margin({ top: 10 })
        .fontColor('#666666')

      // 应用选择
      Text('选择要限制的应用')
        .fontSize(16)
        .margin({ top: 30 })

      Button('选择应用')
        .onClick(() => this.selectApps())
        .margin({ top: 10 })
        .width('80%')

      Text(`已选择 ${this.selectedTokens.length} 个应用`)
        .fontSize(14)
        .margin({ top: 5 })
        .fontColor('#666666')

      // 设置按钮
      Button('设置限制')
        .onClick(() => this.setRestriction())
        .margin({ top: 30 })
        .width('80%')
    }
    .width('100%')
    .height('100%')
    .padding(20)
  }
}

四、完整示例代码

下面是一个更完整的示例,包含了应用访问限制的设置、状态显示和管理功能:

import { guardService, appPicker } from '@kit.ScreenTimeGuardKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';
import { preferences } from '@kit.ArkData';

@Entry
@Component
struct AppsRestrictionManagement {
  // 状态变量
  @State authStatus: string = '未知';
  @State selectedTokens: string[] = [];
  @State restrictionType: string = 'BLOCKLIST_TYPE';
  @State isRestricted: boolean = false;
  @State message: string = '';

  // 用户首选项
  private pref: preferences.Preferences | null = null;

  async aboutToAppear() {
    // 初始化用户首选项
    let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
    this.pref = await preferences.getPreferences(context, 'apps_restriction_data');

    // 加载保存的状态
    await this.loadStatus();

    // 检查授权状态
    await this.checkAuthStatus();
  }

  /**
   * 加载保存的状态
   */
  async loadStatus() {
    try {
      if (this.pref) {
        const tokens = await this.pref.get('selected_tokens', '') as string;
        if (tokens) {
          this.selectedTokens = JSON.parse(tokens);
        }

        const type = await this.pref.get('restriction_type', 'BLOCKLIST_TYPE') as string;
        this.restrictionType = type;

        const restricted = await this.pref.get('is_restricted', false) as boolean;
        this.isRestricted = restricted;
      }
    } catch (err) {
      hilog.error(0x0000, 'AppsRestrictionManagement', 'loadStatus failed');
    }
  }

  /**
   * 保存状态
   */
  async saveStatus() {
    try {
      if (this.pref) {
        await this.pref.put('selected_tokens', JSON.stringify(this.selectedTokens));
        await this.pref.put('restriction_type', this.restrictionType);
        await this.pref.put('is_restricted', this.isRestricted);
        await this.pref.flush();
      }
    } catch (err) {
      hilog.error(0x0000, 'AppsRestrictionManagement', 'saveStatus failed');
    }
  }

  /**
   * 检查授权状态
   */
  async checkAuthStatus() {
    try {
      const status = await guardService.getUserAuthStatus();
      this.authStatus = status === guardService.AuthStatus.AUTHORIZED ? '已授权' : '未授权';
    } catch (err) {
      const message = (err as BusinessError).message;
      const code = (err as BusinessError).code;
      hilog.error(0x0000, 'AppsRestrictionManagement',
        `checkAuthStatus failed with error code: ${code}, message: ${message}`);
    }
  }

  /**
   * 请求用户授权
   */
  async requestAuth() {
    try {
      await guardService.requestUserAuth(
        this.getUIContext().getHostContext() as common.UIAbilityContext
      );
      await this.checkAuthStatus();
      this.message = '授权成功';
    } catch (err) {
      const message = (err as BusinessError).message;
      const code = (err as BusinessError).code;
      this.message = `授权失败: ${message}`;
      hilog.error(0x0000, 'AppsRestrictionManagement',
        `requestUserAuth failed with error code: ${code}, message: ${message}`);
    }
  }

  /**
   * 选择应用
   */
  async selectApps() {
    try {
      const tokens = await appPicker.startAppPicker(
        this.getUIContext().getHostContext() as common.UIAbilityContext,
        { appTokens: this.selectedTokens }
      );
      this.selectedTokens = tokens;
      this.message = `已选择 ${tokens.length} 个应用`;
      hilog.info(0x0000, 'AppsRestrictionManagement', 
        `selected ${tokens.length} apps`);
    } catch (err) {
      const message = (err as BusinessError).message;
      const code = (err as BusinessError).code;
      this.message = `选择应用失败: ${message}`;
      hilog.error(0x0000, 'AppsRestrictionManagement',
        `startAppPicker failed with error code: ${code}, message: ${message}`);
    }
  }

  /**
   * 设置应用访问限制
   */
  async setRestriction() {
    if (this.selectedTokens.length === 0) {
      this.message = '请先选择要限制的应用';
      return;
    }

    try {
      const appInfo: guardService.AppInfo = {
        appTokens: this.selectedTokens
      };

      const restrictionType: guardService.RestrictionType = 
        this.restrictionType === 'BLOCKLIST_TYPE' 
          ? guardService.RestrictionType.BLOCKLIST_TYPE 
          : guardService.RestrictionType.ALLOWLIST_TYPE;

      await guardService.setAppsRestriction(appInfo, restrictionType);
      this.isRestricted = true;
      await this.saveStatus();
      this.message = `应用访问限制设置成功 (${this.getRestrictionTypeDesc()})`;
      hilog.info(0x0000, 'AppsRestrictionManagement', 
        `setAppsRestriction succeeded with type: ${this.restrictionType}`);
    } catch (err) {
      const message = (err as BusinessError).message;
      const code = (err as BusinessError).code;
      this.message = `设置失败: ${message}`;
      hilog.error(0x0000, 'AppsRestrictionManagement',
        `setAppsRestriction failed with error code: ${code}, message: ${message}`);
    }
  }

  /**
   * 获取限制类型描述
   */
  getRestrictionTypeDesc(): string {
    return this.restrictionType === 'BLOCKLIST_TYPE' ? '禁止清单' : '允许清单';
  }

  /**
   * 获取限制类型说明
   */
  getRestrictionTypeDescDetail(): string {
    if (this.restrictionType === 'BLOCKLIST_TYPE') {
      return '禁止访问选中的应用';
    } else {
      return '只允许访问选中的应用';
    }
  }

  build() {
    Column() {
      Text('应用访问限制管理')
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 40 })

      // 消息显示
      Text(this.message)
        .fontSize(14)
        .margin({ top: 10 })
        .fontColor('#666666')

      // 授权状态
      Row() {
        Text('授权状态: ' + this.authStatus)
          .fontSize(16)
          .margin({ top: 20 })
        
        if (this.authStatus === '已授权') {
          Text('✓')
            .fontSize(16)
            .fontColor('#00FF00')
            .margin({ left: 10 })
        } else {
          Button('请求授权')
            .onClick(() => this.requestAuth())
            .margin({ left: 10 })
        }
      }
      .margin({ top: 10 })
      .width('100%')
      .padding({ left: 20, right: 20 })
      .backgroundColor('#F5F5F5')
      .borderRadius(8)

      // 限制状态
      Row() {
        Text('限制状态: ' + (this.isRestricted ? '已开启' : '未开启'))
          .fontSize(16)
          .margin({ top: 20 })
        
        if (this.isRestricted) {
          Text('✓')
            .fontSize(16)
            .fontColor('#00FF00')
            .margin({ left: 10 })
        }
      }
      .margin({ top: 10 })
      .width('100%')
      .padding({ left: 20, right: 20 })
      .backgroundColor('#F5F5F5')
      .borderRadius(8)

      // 限制类型选择
      Text('限制类型')
        .fontSize(16)
        .margin({ top: 30 })

      Row() {
        Button('禁止清单')
          .onClick(() => { this.restrictionType = 'BLOCKLIST_TYPE'; })
          .backgroundColor(this.restrictionType === 'BLOCKLIST_TYPE' ? '#007DFF' : '#F5F5F5')
          .fontColor(this.restrictionType === 'BLOCKLIST_TYPE' ? '#FFFFFF' : '#000000')
          .margin({ right: 10 })

        Button('允许清单')
          .onClick(() => { this.restrictionType = 'ALLOWLIST_TYPE'; })
          .backgroundColor(this.restrictionType === 'ALLOWLIST_TYPE' ? '#007DFF' : '#F5F5F5')
          .fontColor(this.restrictionType === 'ALLOWLIST_TYPE' ? '#FFFFFF' : '#000000')
          .margin({ left: 10 })
      }
      .margin({ top: 10 })
      .width('80%')

      // 限制类型说明
      Text(this.getRestrictionTypeDesc() + ': ' + this.getRestrictionTypeDescDetail())
        .fontSize(14)
        .margin({ top: 10 })
        .fontColor('#666666')

      // 应用选择
      Text('选择要限制的应用')
        .fontSize(16)
        .margin({ top: 30 })

      Button('选择应用')
        .onClick(() => this.selectApps())
        .margin({ top: 10 })
        .width('80%')

      Text(`已选择 ${this.selectedTokens.length} 个应用`)
        .fontSize(14)
        .margin({ top: 5 })
        .fontColor('#666666')

      // 设置按钮
      Button('设置限制')
        .onClick(() => this.setRestriction())
        .margin({ top: 30 })
        .width('80%')
    }
    .width('100%')
    .height('100%')
    .padding(20)
  }
}

五、注意事项

🥦 西兰花警告:

  1. 必须先获得用户授权: 设置应用访问限制之前,必须先请求用户授权,否则会报错

  2. 限制类型选择正确:

    • 禁止清单: 限制选中的应用(黑名单)
    • 允许清单: 只允许选中的应用(白名单)
    • 这两种类型的含义完全相反,要仔细选择
  3. 空列表的特殊含义:

    • 空列表 + 禁止清单 = 不限制任何应用
    • 空列表 + 允许清单 = 限制除系统应用、管控应用外的所有应用
  4. 重复调用覆盖: 对同一个管控应用,重复调用会以最新的限制为准

  5. 应用 Token 要保存: 应用 Token 需要保存好,用于后续的解除限制操作

  6. 系统应用不受影响: 时钟、电话等系统内置允许清单应用不受限制影响

  7. 管控应用自身不受影响: 管控发起应用本身不受限制影响


六、使用场景

应用访问限制功能可以用于以下场景:

1. 家长控制

  • 禁止清单: 不让孩子访问游戏、社交等应用
  • 允许清单: 只允许孩子访问学习类应用

2. 专注模式

  • 禁止清单: 工作时禁止访问社交、娱乐应用
  • 允许清单: 只允许访问工作相关的应用

3. 设备共享

  • 允许清单: 设备共享给他人时,只允许访问特定应用
  • 禁止清单: 防止他人访问隐私应用

七、文档资源

官方文档链接:


八、总结

应用访问限制功能可以让你轻松实现对应用的访问控制,支持禁止清单和允许清单两种模式。

核心要点:

  1. 禁止清单: 限制选中的应用(黑名单模式)
  2. 允许清单: 只允许选中的应用(白名单模式)
  3. 空列表有特殊含义,要根据限制类型正确理解
  4. 重复调用会以最新的限制为准
  5. 系统应用和管控应用不受限制影响
  6. 应用 Token 需要保存好,用于后续解除限制

应用访问限制就像是给设备设置一个"准入名单"或"禁止名单",让你可以灵活控制应用访问权限 _


下一步行动

建议你:

  1. 先请求用户授权
  2. 测试禁止清单功能
  3. 测试允许清单功能
  4. 测试空列表的情况
  5. 结合下一篇的解除限制功能,实现完整的限制管理
  6. 根据实际需求调整限制策略

记住,不教理论,只给你能跑的代码和避坑指南! _


我是盐焗西兰花,
不教理论,只给你能跑的代码和避坑指南。
下期见!🥦

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐