在这里插入图片描述

前言

Kiosk(商用自助锁定模式)是鸿蒙面向门店收银机、自助取票机、政务终端、广告一体机的企业级管控能力,核心作用:
设备开机后仅运行当前应用,屏蔽返回键、Home桌面、下拉通知栏、多任务、分屏、设置入口,用户无法退出应用、切换其他程序,防止客户误操作系统。
API26(鸿蒙7)kioskManager 统一收敛至 @kit.AbilityKit,属于企业受限系统权限,普通个人应用无法使用,必须企业开发者认证+AGC申请受控权限Profile。

一、核心前置门槛(开发前必须完成,否则API直接报错)

1.1 账号资质要求

  1. 华为开发者联盟企业实名认证,个人账号无权限申请Kiosk管控权限;
  2. 设备为鸿蒙企业版/商用自助终端(普通消费手机仅调试,无法正式商用锁机);
  3. 应用归属企业商用场景(自助终端、政务、零售门店),上架审核需提供商用场景说明材料。

1.2 关键受限权限说明

核心权限:ohos.permission.ENTERPRISE_SET_KIOSK

  • 权限等级:system_grant 系统受控权限,不能动态弹窗申请
  • 获取方式:AGC创建发布Profile时勾选该权限,审核通过后下载签名Profile打包;
  • 作用:允许应用进入/退出Kiosk单应用锁定模式、查询锁机状态。

1.3 完整前置流程(四步)

  1. 企业账号完成认证;
  2. AGC创建应用,申请发布Profile,勾选ENTERPRISE_SET_KIOSK并提交商用场景说明;
  3. 下载带权限的签名p7b Profile、证书;
  4. 工程配置正式企业签名,调试/打包均使用该签名,自动签名无受控权限无法调用Kiosk API。

二、工程配置全量代码

2.1 module.json5 权限、窗口、自启配置

{
  "module": {
    "name": "entry",
    "type": "har",
    "deviceTypes": ["tablet", "phone"],
    "requestPermissions": [
      {
        "name": "ohos.permission.ENTERPRISE_SET_KIOSK",
        "reason": "$string:kiosk_lock_reason",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "always"
        }
      },
      // 全屏、窗口管控配套权限
      {
        "name": "ohos.permission.WINDOW_FULLSCREEN",
        "reason": "$string:fullscreen_reason",
        "usedScene": { "abilities": ["EntryAbility"], "when": "always" }
      }
    ],
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets",
        "exported": true,
        "launchType": "singleTask",
        "skills": [],
        "metadata": [
          // 开机自启动(商用终端必备)
          {
            "name": "ohos.ability.startup",
            "value": "auto_start"
          }
        ],
        "window": {
          "designWidth": 720,
          "autoHiddenNavigationBar": true,
          "autoHiddenStatusBar": true
        }
      }
    ]
  }
}

2.2 oh-package.json5 标准@kit导入依赖

"dependencies": {
  "@kit.AbilityKit": "1.0.0",
  "@kit.ArkUI": "1.0.0",
  "@kit.PerformanceAnalysisKit": "1.0.0",
  "@kit.BasicServicesKit": "1.0.0"
}

三、Kiosk核心API能力总览(@kit.AbilityKit.kioskManager)

API 作用
enterKioskMode(context) 进入单应用锁定模式,屏蔽所有系统逃逸入口
exitKioskMode(context) 退出锁机(管理员密码/后台运维使用)
getKioskStatus() 查询当前锁机状态:是否锁定、锁定应用包名
on("kioskChange", callback) 监听锁机状态变更(被强制退出、系统切换)

锁机后系统自动限制效果

  1. 屏蔽底部虚拟导航栏(返回、主页、多任务键消失);
  2. 顶部状态栏/通知栏下拉手势拦截,无法调出控制中心;
  3. Home键、多任务手势失效,无法返回桌面;
  4. 分屏、悬浮窗、自由窗口全部禁用;
  5. 其他应用无法前台拉起,系统仅保留当前应用进程;
  6. 屏蔽系统设置快捷入口、下拉菜单关机/重启选项。

四、完整分层实战代码

4.1 第一层:EntryAbility 生命周期自动进锁+全屏隐藏系统栏

应用切前台自动校验并进入Kiosk,页面加载前设置全屏无系统UI:

import { UIAbility, Want, window, kioskManager, common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit';

const TAG = "KioskAbility";
const DOMAIN = 0x0005;

export default class EntryAbility extends UIAbility {
  uiContext: common.UIAbilityContext | null = null;

  onCreate(want: Want, launchParam: common.LaunchParam): void {
    this.uiContext = this.context as common.UIAbilityContext;
    hilog.info(DOMAIN, TAG, "商用Kiosk应用启动");
  }

  // 窗口创建,全屏隐藏状态栏、导航栏
  onWindowStageCreate(windowStage: window.WindowStage): void {
    const mainWin = windowStage.getMainWindow();
    mainWin.then(win => {
      // 全屏模式
      win.setWindowLayoutFullScreen(true);
      // 透明系统栏,彻底隐藏
      win.setWindowSystemBarProperties({
        statusBarOpacity: 0,
        navigationBarOpacity: 0,
        statusBarBackgroundColor: "#00000000",
        navigationBarBackgroundColor: "#00000000"
      });
    });
    // 加载业务页面
    windowStage.loadContent("pages/KioskIndex", (err) => {
      if (err.code) hilog.error(DOMAIN, TAG, `页面加载失败:${err.message}`);
    });
  }

  // 切前台自动进入锁机模式(核心)
  onForeground(): void {
    this.autoEnterKiosk();
  }

  // 自动校验并进入Kiosk锁定
  private async autoEnterKiosk() {
    if (!this.uiContext) return;
    try {
      const status = kioskManager.getKioskStatus();
      // 已为本应用锁定,无需重复进入
      if (status.isKioskMode && status.kioskBundleName === this.uiContext.bundleName) {
        hilog.info(DOMAIN, TAG, "已处于Kiosk锁定模式");
        return;
      }
      // 进入单应用锁定
      await kioskManager.enterKioskMode(this.uiContext);
      hilog.info(DOMAIN, TAG, "成功进入商用Kiosk锁机模式");
    } catch (err) {
      const e = err as BusinessError;
      // 错误码160001:系统已存在其他Kiosk应用,需先退出原有锁机
      if (e.code === 160001) {
        hilog.error(DOMAIN, TAG, "当前设备已有其他应用锁定,无法进入");
      } else {
        hilog.error(DOMAIN, TAG, `进入Kiosk失败 code:${e.code} msg:${e.message}`);
      }
    }
  }

  // 监听锁机状态变更回调
  onBackground(): void {
    kioskManager.off("kioskChange");
  }
}

4.2 第二层:业务主页面(管理员退出锁机入口)

普通用户无退出按钮,仅管理员输入密码后调用exitKioskMode退出锁机,支持密码校验、状态实时展示:

import { ComponentV2, Local } from '@kit.ArkUI';
import { kioskManager, common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit';

const TAG = "KioskPage";
const ADMIN_PWD = "admin123456"; // 管理员退出密码,生产环境加密存储

@Entry
@ComponentV2
struct KioskIndex {
  @Local kioskEnable: boolean = false;
  @Local inputPwd: string = "";
  @Local tipText: string = "商用自助终端 · 已锁定,仅管理员可退出";
  private uiCtx: common.UIAbilityContext | null = null;

  aboutToAppear() {
    this.uiCtx = getContext(this) as common.UIAbilityContext;
    this.refreshKioskStatus();
    // 监听锁机状态变化
    kioskManager.on("kioskChange", () => {
      this.refreshKioskStatus();
    });
  }

  aboutToDisappear() {
    kioskManager.off("kioskChange");
  }

  // 刷新当前锁机状态
  private refreshKioskStatus() {
    const status = kioskManager.getKioskStatus();
    this.kioskEnable = status.isKioskMode;
    if (this.kioskEnable) {
      this.tipText = `锁定生效,当前应用:${status.kioskBundleName}`;
    } else {
      this.tipText = "未进入Kiosk锁定模式";
    }
  }

  // 管理员退出锁机模式
  private async exitLockMode() {
    if (this.inputPwd !== ADMIN_PWD) {
      this.tipText = "密码错误,无法退出锁定";
      return;
    }
    if (!this.uiCtx) return;
    try {
      await kioskManager.exitKioskMode(this.uiCtx);
      this.tipText = "已成功退出Kiosk锁机模式";
      this.inputPwd = "";
    } catch (err) {
      const e = err as BusinessError;
      this.tipText = `退出失败:${e.message}`;
      hilog.error(0x0005, TAG, `退出Kiosk异常:${JSON.stringify(err)}`);
    }
  }

  build() {
    Column({ space: 30 }) {
      Text("商用自助终端 Kiosk 锁定演示")
        .fontSize(24)
        .fontWeight(FontWeight.Bold)
        .margin({ top: 40 });

      Text(this.tipText)
        .fontSize(16)
        .fontColor(this.kioskEnable ? "#00B42A" : "#F53F3F");

      // 业务自助交互区域(客户操作区)
      Column() {
        Text("客户业务操作区")
          .fontSize(20)
        Button("业务办理")
          .width(200)
          .height(50)
          .backgroundColor("#0A59F7")
      }
      .width("90%")
      .height(220)
      .padding(20)
      .backgroundColor("#F5F7FA")
      .borderRadius(12);

      // 管理员退出区域(隐藏给普通客户,运维使用)
      Column({ space: 12 }) {
        Text("管理员退出锁机(仅运维)")
          .fontSize(14)
          .fontColor("#666");
        TextInput({ text: this.inputPwd })
          .width("90%")
          .height(44)
          .type(InputType.Password)
          .onChange(v => this.inputPwd = v);
        Button("验证密码退出锁定")
          .width("90%")
          .height(48)
          .backgroundColor("#F53F3F")
          .onClick(() => this.exitLockMode());
      }
      .width("90%")
      .padding(16)
      .backgroundColor("#FFFFFF")
      .borderRadius(12);

      Blank();
      Text("💡 锁机后无法下拉通知栏、返回桌面、切换其他应用")
        .fontSize(12)
        .fontColor("#888888")
        .margin({ bottom: 40 });
    }
    .width("100%")
    .height("100%")
    .backgroundColor("#F8F9FA");
  }
}

五、配套加固方案(多层防逃逸,商用必备)

仅靠Kiosk模式仍存在少量逃逸路径,商用终端需叠加四层防护:

5.1 防护1:开机自启

metadata:ohos.ability.startup:auto_start,设备上电自动拉起应用并进入锁机,无需人工点开。

5.2 防护2:窗口全屏+隐藏系统栏

Ability窗口阶段强制隐藏状态栏、导航栏,无任何系统UI可触发下拉手势。

5.3 防护3:限制应用被后台销毁后自动重启

配置launchType:singleTask,系统内存回收后自动重启Ability,重新进入Kiosk锁机。

5.4 防护4:设备MDM管控(高阶商用)

企业批量终端搭配HEM设备管理平台:

  1. 禁用USB调试、文件传输;
  2. 屏蔽设置、应用市场、浏览器;
  3. 限制物理按键(音量、电源长按);
  4. 远程下发指令进入/退出Kiosk,无需现场输入密码。

六、调试与打包完整流程

  1. AGC申请受控Profile:勾选ohos.permission.ENTERPRISE_SET_KIOSK,提交商用自助终端场景材料,等待审核(1~3工作日);
  2. 配置企业正式签名:DevEco Studio导入下载的p12证书、p7b Profile;
  3. 真机调试:仅企业商用设备支持,普通消费手机调用API会报权限不足;模拟器无Kiosk系统服务,无法调试;
  4. 打包Release商用包:Build → Build Hap(s),使用带权限的签名;
  5. 设备安装验证:安装后启动自动进入锁机,测试下拉通知、返回手势、Home键全部失效。

七、高频踩坑避坑大全

坑1:enterKioskMode 报错 权限不足

  1. 未使用企业认证账号;
  2. AGC申请Profile时未勾选ENTERPRISE_SET_KIOSK
  3. 使用DevEco自动调试签名,无受控权限;
  4. module.json5未声明对应权限。

坑2:错误码160001 已存在其他Kiosk应用

一台设备同一时间仅允许一个应用锁定,需先退出原有应用的Kiosk模式,再执行当前应用进入锁机。

坑3:切换分屏/下拉通知栏仍能调出系统UI

  • 未在WindowStage设置全屏+透明系统栏;
  • 窗口配置未开启autoHiddenNavigationBar/autoHiddenStatusBar
  • 设备非企业商用固件,消费版系统管控能力受限。

坑4:应用后台被杀后,锁机失效

解决方案:

  1. 配置开机自启;
  2. singleTask单实例启动模式;
  3. onForeground自动执行autoEnterKiosk,切前台重新上锁。

坑5:普通个人手机无法使用Kiosk API

底层限制:ENTERPRISE_SET_KIOSK仅对企业商用设备、企业MDM应用开放,个人消费手机无系统授权通道。

坑6:退出锁机后系统UI异常(导航栏不恢复)

调用exitKioskMode后,重启窗口重置系统栏属性,或重启应用恢复默认窗口样式。

八、商用生产环境最佳实践

  1. 密码安全:管理员退出密码禁止硬编码,使用SecureStorage加密存储,支持后台远程修改;
  2. 日志审计:Kiosk进入/退出、密码验证全部写入系统日志,可追溯运维操作;
  3. 异常兜底:onForeground自动重新上锁,防止进程异常解锁;
  4. 分层UI隔离:客户操作区与管理员退出面板视觉隔离,现场隐藏密码输入区域;
  5. 批量运维:多终端接入HEM MDM平台,远程一键切换锁机状态,无需现场操作;
  6. 断电保护:开启开机自启,断电重启自动恢复锁定,无人值守稳定运行。

总结

鸿蒙7 Kiosk商用锁定是面向线下自助终端的企业级管控方案,核心依赖kioskManager套件+企业受控权限,实现单应用完全锁定、屏蔽所有系统逃逸入口。
完整落地分为资质申请→工程配置→Ability自动上锁→管理员密码退出→多层加固五步,普通个人应用无法使用,仅企业商用自助设备适配。开发重点做好权限申请、前台自动重锁、窗口全屏隐藏系统栏三层核心逻辑,即可满足门店、政务、零售终端无人值守商用场景。

Logo

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

更多推荐