在自助点餐机、门店收银终端、展厅查询机、工业平板这类商用场景中,最核心的需求就是设备锁定 :让设备开机后自动运行指定应用,用户无法退出、无法切换到桌面或其他 App,防止误操作和恶意篡改。

鸿蒙 7(API 26)中的 Kiosk 自助锁定模式 ,就是专门解决这类问题的系统级能力。它隶属于 @kit.AbilityKit 程序框架套件,由系统底层管控,应用层只需几行代码就能实现全屏锁定,安全性远高于应用层模拟的「伪全屏」。
本文从核心原理、权限配置、完整实战到最佳实践,带你彻底搞懂 Kiosk 模式,落地商用门店级的单应用锁定方案。
一、什么是 Kiosk 锁屏模式
1.1 核心定义
Kiosk 模式是鸿蒙系统提供的设备级单应用锁定能力:开启后,设备将被锁定在指定应用内,用户无法返回桌面、无法切换应用、无法下拉控制中心、无法使用系统手势,只能操作当前应用的功能。
它不是应用自己做的全屏模拟,而是系统级的管控,底层由 AbilityKit 框架 + 系统设备管控服务共同实现,普通用户无法绕过,非常适合无人值守的商用终端场景。
1.2 典型商用场景
- 🏪 连锁门店:自助点餐机、自助收银终端
- 🏢 政企大厅:政务查询机、业务办理终端
- 🏭 工业场景:车间生产平板、设备操控终端
- 🎯 展览展厅:互动查询屏、产品演示终端
- 📚 教育场景:考试专用平板、教学一体机
1.3 与普通全屏的本质区别
很多新手会用「隐藏状态栏 + 禁用返回键」模拟锁定效果,和系统 Kiosk 模式完全不是一个层级:
| 对比项 | 应用层模拟全屏 | 系统 Kiosk 模式 |
|---|---|---|
| 管控层级 | 应用层,可被绕过 | 系统底层,无法绕过 |
| 系统手势 | 只能禁用部分 | 全部系统手势失效 |
| 多任务切换 | 仍可被切走 | 完全无法切换应用 |
| 下拉控制中心 | 无法禁止 | 完全禁止下拉 |
| 开机自启动 | 需要额外配置 | 可配合实现开机直达 |
| 安全性 | 低,容易被退出 | 高,系统级保障 |
二、核心架构与 API 说明
Kiosk 模式采用「管控层 + 应用层」的双层架构,职责分离,符合企业级安全规范。
2.1 两层架构
-
MDM 管控层(设备管理应用)
- 负责配置允许进入 Kiosk 模式的应用白名单
- 可远程下发锁定/解锁指令
- 需要企业级
ENTERPRISE_SET_KIOSK权限,通过华为 HEM 企业设备管理平台授权 - 适合连锁门店、企业 IT 统一管理场景
-
业务应用层(门店 App)
- 被加入白名单后,可主动调用接口进入/退出 Kiosk 模式
- 只需要关注自身业务逻辑,不用处理底层管控
- 导入
kioskManager即可使用,开发门槛极低
💡 单设备调试场景:可通过开发者选项或 adb 命令将测试应用加入白名单,无需完整 MDM 部署。
2.2 核心 API 速览
所有能力统一从 @kit.AbilityKit 导入,仅支持 Stage 模型,API 20 及以上可用。
typescript
import { kioskManager } from '@kit.AbilityKit';
| API | 作用 |
|---|---|
kioskManager.enterKioskMode(context) |
进入 Kiosk 锁定模式 |
kioskManager.exitKioskMode(context) |
退出 Kiosk 锁定模式 |
kioskManager.getKioskStatus() |
获取当前 Kiosk 状态(是否锁定、锁定的包名) |
2.3 状态结构体 KioskStatus
typescript
interface KioskStatus {
isKioskMode: boolean; // 当前是否处于 Kiosk 模式
kioskBundleName: string; // 当前锁定的应用包名
kioskBundleUid: number; // 锁定应用的 UID
}
三、前置配置与权限说明
这是新手最高频的踩坑点:不是随便一个应用都能调用 Kiosk 接口,必须先被系统加入允许名单,否则调用会直接报错。
3.1 企业级正式部署
商用正式环境通过企业 MDM 平台配置:
- 在华为 HEM 企业设备管理平台注册设备
- 通过 MDM 应用调用
setAllowedKioskApps接口,将业务 App 加入 Kiosk 白名单 - 设备端业务 App 即可正常调用进入/退出接口
- 需要
ohos.permission.ENTERPRISE_SET_KIOSK系统级权限,仅对企业 MDM 应用开放
3.2 开发调试配置
开发阶段可通过 adb 命令快速将测试应用加入白名单,无需部署完整 MDM:
bash
# 替换为你的应用包名
adb shell set allowed_kiosk_apps com.example.storekiosk
3.3 应用侧清单配置
业务应用本身不需要申请特殊权限,只需要确保:
- 工程为 Stage 模型
compileSdkVersion≥ API 20- 应用已被加入 Kiosk 允许名单
四、完整实战:门店自助终端 Kiosk 实现
下面实现一个典型的门店自助点餐终端页面,包含:
- 应用启动自动进入 Kiosk 模式
- 隐藏管理员入口,输入密码可退出锁定
- 实时显示当前锁定状态
- 异常兜底逻辑
4.1 入口 Ability 自动进入 Kiosk
在应用主 Ability 的 onForeground 中自动进入锁定模式,保证切回前台也会保持锁定。

typescript
import { UIAbility, AbilityConstant, Want } from '@kit.AbilityKit';
import { kioskManager } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';
const TAG = 'StoreKioskAbility';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(0x0000, TAG, '应用创建');
}
onWindowStageCreate(windowStage: window.WindowStage): void {
// 开启全屏布局,隐藏系统栏
windowStage.getMainWindow().then(win => {
win.setWindowLayoutFullScreen(true);
win.setWindowSystemBarProperties({
statusBarBackgroundColor: '#00000000',
navigationBarBackgroundColor: '#00000000'
});
});
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
hilog.error(0x0000, TAG, `页面加载失败: ${JSON.stringify(err)}`);
}
});
}
onForeground(): void {
// 进入前台自动尝试进入 Kiosk 模式
this.enterKioskMode();
}
/**
* 进入 Kiosk 锁定模式
*/
private async enterKioskMode() {
try {
// 先检查是否已经在 Kiosk 模式
const status = kioskManager.getKioskStatus();
if (status.isKioskMode && status.kioskBundleName === this.context.bundleName) {
hilog.info(0x0000, TAG, '已处于Kiosk模式');
return;
}
await kioskManager.enterKioskMode(this.context);
hilog.info(0x0000, TAG, '成功进入Kiosk锁定模式');
} catch (err) {
hilog.error(0x0000, TAG, `进入Kiosk失败: ${JSON.stringify(err)}`);
}
}
onDestroy(): void {
// 应用销毁时可选择是否退出 Kiosk,门店终端一般不退出
hilog.info(0x0000, TAG, '应用销毁');
}
}
4.2 主页面:管理员退出入口
页面上做一个隐蔽的管理员入口,连续点击指定区域 5 次弹出密码输入框,验证通过后可退出 Kiosk 模式。


typescript
import { kioskManager } from '@kit.AbilityKit';
import { promptAction, TextInput } from '@kit.ArkUI';
import { hilog } from '@kit.PerformanceAnalysisKit';
const TAG = 'StoreKioskPage';
// 管理员退出密码,实际项目建议加密存储或服务端验证
const ADMIN_PASSWORD = 'admin123';
@Entry
@Component
struct StoreKioskPage {
@State isKioskMode: boolean = false;
@State showPasswordDialog: boolean = false;
@State inputPassword: string = '';
// 连续点击计数
private clickCount: number = 0;
private lastClickTime: number = 0;
private uiContext = getContext(this) as any;
aboutToAppear() {
this.refreshKioskStatus();
}
/**
* 刷新 Kiosk 状态
*/
refreshKioskStatus() {
try {
const status = kioskManager.getKioskStatus();
this.isKioskMode = status.isKioskMode;
} catch (err) {
hilog.error(0x0000, TAG, `获取状态失败: ${JSON.stringify(err)}`);
this.isKioskMode = false;
}
}
/**
* 连续点击logo 5次触发管理员入口
*/
onLogoClick() {
const now = Date.now();
if (now - this.lastClickTime > 2000) {
this.clickCount = 0;
}
this.lastClickTime = now;
this.clickCount++;
if (this.clickCount >= 5) {
this.clickCount = 0;
this.showPasswordDialog = true;
}
}
/**
* 验证密码并退出 Kiosk
*/
async exitKioskMode() {
if (this.inputPassword !== ADMIN_PASSWORD) {
promptAction.showToast({ message: '密码错误' });
return;
}
try {
await kioskManager.exitKioskMode(this.uiContext);
this.isKioskMode = false;
this.showPasswordDialog = false;
this.inputPassword = '';
promptAction.showToast({ message: '已退出锁定模式' });
hilog.info(0x0000, TAG, '管理员退出Kiosk模式');
} catch (err) {
hilog.error(0x0000, TAG, `退出失败: ${JSON.stringify(err)}`);
promptAction.showToast({ message: '退出失败,请检查权限' });
}
}
build() {
Stack() {
// 主界面:门店自助点餐首页
Column({ space: 30 }) {
// 顶部Logo区域(连续点击5次触发管理员入口)
Text('🍔 自助点餐系统')
.fontSize(36)
.fontWeight(FontWeight.Bold)
.fontColor('#E65100')
.margin({ top: 80 })
.onClick(() => this.onLogoClick());
Text('欢迎使用自助点餐服务')
.fontSize(20)
.fontColor('#333333');
Blank();
// 功能入口
Grid() {
GridItem() {
this.buildMenuIcon('🍔', '扫码点餐');
}
GridItem() {
this.buildMenuIcon('🛒', '我的订单');
}
GridItem() {
this.buildMenuIcon('🎫', '优惠券');
}
GridItem() {
this.buildMenuIcon('📞', '呼叫服务');
}
}
.columnsTemplate('1fr 1fr')
.columnsGap(24)
.rowsGap(24)
.width('80%');
Blank();
// 状态提示
Text(this.isKioskMode ? '🔒 设备已锁定' : '⚠️ 设备未锁定')
.fontSize(14)
.fontColor(this.isKioskMode ? '#00B578' : '#FF4D4F')
.margin({ bottom: 40 });
}
.width('100%')
.height('100%')
.backgroundColor('#FFF8E1');
// 密码输入弹窗
if (this.showPasswordDialog) {
Column({ space: 20 }) {
Text('管理员验证')
.fontSize(18)
.fontWeight(FontWeight.Medium);
TextInput({ placeholder: '请输入管理员密码' })
.type(InputType.Password)
.width('100%')
.height(44)
.onChange((val) => this.inputPassword = val);
Row({ space: 12 }) {
Button('取消')
.layoutWeight(1)
.height(44)
.backgroundColor('#F5F5F5')
.fontColor('#333333')
.onClick(() => {
this.showPasswordDialog = false;
this.inputPassword = '';
});
Button('确认')
.layoutWeight(1)
.height(44)
.backgroundColor('#0A59F7')
.onClick(() => this.exitKioskMode());
}
.width('100%');
}
.width('80%')
.padding(24)
.backgroundColor('#FFFFFF')
.borderRadius(16)
.shadow({ radius: 16, color: '#40000000' });
}
}
.width('100%')
.height('100%');
}
@Builder
buildMenuIcon(icon: string, title: string) {
Column({ space: 12 }) {
Text(icon)
.fontSize(48);
Text(title)
.fontSize(16)
.fontColor('#333333');
}
.width('100%')
.height(120)
.backgroundColor('#FFFFFF')
.borderRadius(16)
.justifyContent(FlexAlign.Center)
.onClick(() => {
promptAction.showToast({ message: `进入${title}` });
});
}
}
五、商用落地最佳实践
1. 开机自启动直达
门店终端通常要求开机自动进入应用并锁定。可通过 MDM 配置开机自启动应用,配合 Ability 前台自动进 Kiosk 的逻辑,实现开机直达业务界面,全程无需人工干预。
2. 异常崩溃自动恢复
Kiosk 模式下,如果应用崩溃,系统会自动重新拉起应用,保证终端始终可用。建议在应用内增加崩溃日志上报,便于运维排查问题。
3. 分级权限管理
- 普通用户:完全锁定,只能操作业务功能
- 店员:可执行锁屏、重启等基础操作
- 管理员:可退出 Kiosk、修改配置、进行系统维护
不同级别设置不同密码或验证方式,保证安全。
4. 配合保活机制
结合系统应用保活能力,保证应用在后台不会被系统杀死,7×24 小时稳定运行。
六、新手高频踩坑避坑指南
1. 调用 enterKioskMode 直接报错
- 最常见原因:应用未被加入 Kiosk 允许白名单
- 解决:开发环境用 adb 命令设置允许名单;正式环境通过 MDM 平台配置
- 验证 :先调用
getKioskStatus()确认接口可用,再执行进入操作
2. 进入 Kiosk 后不知道怎么退出
- 说明:Kiosk 模式下系统手势全部失效,普通用户无法退出
- 方案:应用内必须预留隐蔽的管理员退出入口,如连续点击、密码验证;也可通过 MDM 远程下发退出指令
3. 以为需要申请 Kiosk 权限
- 说明:业务应用本身不需要申请权限,调用权限在 MDM 管控侧
- 误区 :不要在业务应用清单里加
ENTERPRISE_SET_KIOSK,这个权限是给 MDM 应用用的,普通应用申请了也不会通过
4. 模拟器无法调试 Kiosk
- 说明:Kiosk 是系统级管控能力,模拟器不支持完整的锁定效果
- 方案:逻辑代码可在模拟器编译验证,真实锁定效果必须用真机调试
5. 页面销毁导致退出 Kiosk
- 说明:应用内页面跳转、Ability 切换不会自动退出 Kiosk
- 注意 :只有主动调用
exitKioskMode或 MDM 下发指令,才会解除锁定
总结
Kiosk 模式是鸿蒙面向商用终端场景的核心差异化能力,它把「单应用锁定」这个原本需要定制 ROM 才能实现的功能,封装成了标准的 AbilityKit 接口,开发者只需几行代码就能实现工业级的设备锁定效果。
对于门店自助终端、政企查询机这类场景,Kiosk 模式 + 开机自启 + 崩溃自动恢复的组合方案,完全可以替代传统的定制系统方案,大幅降低开发和运维成本。