HarmonyOS 6】静态和动态添加应用快捷方式详解
一、前言
在功能日益复杂的应用中,用户往往需要多步操作才能找到常用功能。而应用快捷方式能让用户一键直达核心功能,既提升操作效率,也能增强用户对应用的粘性。想象一下,每天下班都要打开地图 App 搜索回家路线,如果能直接在桌面生成"一键回家"的快捷入口,体验将多么不同。
本文结合实际开发场景,详细分享 HarmonyOS 中两种快捷方式的实现方法,包括静态快捷方式配置和应用内动态添加,全程基于单 HAP 包场景(多 HAP 包配置逻辑一致)。
阅读本文你将掌握:
-
静态快捷方式的完整配置流程(配置文件编写 → 模块注册 → 页面跳转)
-
动态快捷方式的代码实现方法(ShortcutManager API 使用)
-
快捷方式的参数传递与页面路由机制
-
常见问题排查与最佳实践
二、快捷方式技术概述
2.1 什么是应用快捷方式
应用快捷方式(Shortcuts)是一种在系统中创建的、可以快速访问应用程序或特定功能的链接。它通常出现在长按应用图标时,以图标和文字形式展示在应用图标上方,用户点击即可迅速启动对应的应用组件。
快捷方式的核心价值在于:
-
提升效率:节省查找和打开对应组件的时间
-
个性化定制:创建多个快捷方式满足个性化工作流程和操作偏好
-
减少操作深度:不用一步步进入一二三级页面,而是直达目标页
2.2 静态快捷方式 vs 动态快捷方式
| 对比维度 | 静态快捷方式 | 动态快捷方式 |
|---|---|---|
| 定义方式 | 通过配置文件预先定义 | 通过代码在运行时添加 |
| 变更能力 | 不可变更,固定不变 | 可根据应用状态动态变化 |
| 适用场景 | 高频固定功能(如"回家导航""新建便签") | 用户自定义、上下文相关的功能入口 |
| 配置位置 | resources/base/profile/shortcuts_config.json |
代码中通过 ShortcutManager API 操作 |
| 权限要求 | 无需额外权限 | 需申请 ohos.permission.INSTALL_SHORTCUT |
2.3 技术实现原理
快捷方式的实现遵循 "配置即生成" 的设计理念,其核心链路可分解为:
-
配置声明:通过 JSON 文件定义快捷方式元数据(shortcutId、label、icon、wants)
-
系统注册:在应用配置清单(module.json5)中声明快捷方式资源
-
动态路由:UIAbility 接收参数进行页面跳转
每个快捷方式必须包含 四要素:
-
shortcutId:唯一标识符 -
label:显示文本 -
icon:图标资源 -
wants:跳转配置(包名、模块名、组件名、自定义参数)
三、静态快捷方式:基础配置与快速跳转
静态快捷方式是通过配置文件预先定义的快捷方式,用户长按应用图标即可看到。
3.1 完整实现步骤
步骤一:创建目标页面并配置路由
首先创建快捷方式对应的功能页面,页面需用 @Entry 装饰器修饰。
创建页面文件(以 GoHouse.ets 和 GoCompany.ets 为例):
typescript
// entry/src/main/ets/pages/GoHouse.ets
@Entry
@Component
struct GoHouse {
build() {
Column() {
Text('回家导航页面')
.fontSize(30)
.margin({ top: 100 })
}
.width('100%')
.height('100%')
}
}
typescript
// entry/src/main/ets/pages/GoCompany.ets
@Entry
@Component
struct GoCompany {
build() {
Column() {
Text('去公司导航页面')
.fontSize(30)
.margin({ top: 100 })
}
.width('100%')
.height('100%')
}
}
然后在 resources/base/profile/main_pages.json 中添加页面路由:
json
{
"src": [
"pages/Index",
"pages/GoHouse",
"pages/GoCompany"
]
}
注意:目标页面必须已在
main_pages.json中注册,否则路由跳转会失败。
步骤二:编写快捷方式配置文件
在 resources/base/profile/ 目录下新建 shortcuts_config.json 文件。
json
{
"shortcuts": [
{
"shortcutId": "id_company",
"label": "$string:Go_to_the_Company",
"icon": "$media:company",
"wants": [
{
"bundleName": "com.example.desktopshortcuts",
"moduleName": "entry",
"abilityName": "EntryAbility",
"parameters": {
"shortCutKey": "CompanyPage"
}
}
]
},
{
"shortcutId": "id_house",
"label": "$string:Go_to_House",
"icon": "$media:house",
"wants": [
{
"bundleName": "com.example.desktopshortcuts",
"moduleName": "entry",
"abilityName": "EntryAbility",
"parameters": {
"shortCutKey": "HousePage"
}
}
]
}
]
}
配置字段详解:
| 字段 | 说明 | 约束 |
|---|---|---|
shortcutId |
快捷方式唯一标识 | 不超过 63 字节 |
label |
显示文本 | 支持字符串或资源索引(如 $string:xxx) |
icon |
图标资源索引 | 如 $media:xxx |
wants |
跳转配置数组 | 包含 bundleName、moduleName、abilityName、parameters |
parameters |
自定义参数 | 用于区分不同的快捷方式 |
步骤三:在 module.json5 中关联配置
在 module.json5 的 abilities 标签下添加 metadata 配置,指向快捷方式配置文件:
json
{
"module": {
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"skills": [
{
"entities": ["entity.system.home"],
"actions": ["ohos.want.action.home"]
}
],
"metadata": [
{
"name": "ohos.ability.shortcuts",
"resource": "$profile:shortcuts_config"
}
]
}
]
}
}
关键点:
name必须固定为"ohos.ability.shortcuts";resource指向shortcuts_config.json文件(不含扩展名)。
步骤四:实现页面跳转逻辑
在 EntryAbility.ets 中实现跳转逻辑:
typescript
// entry/src/main/ets/entryability/EntryAbility.ets
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
import hilog from '@ohos.hilog';
import UIAbility from '@ohos.app.ability.UIAbility';
import Want from '@ohos.app.ability.Want';
import window from '@ohos.window';
import router from '@ohos.router';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
this.goToSpecifyPage(want);
}
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onNewWant');
this.goToSpecifyPage(want);
}
goToSpecifyPage(want: Want): void {
let shortCutKey = want.parameters?.shortCutKey;
if (shortCutKey === 'CompanyPage') {
router.pushUrl({ url: 'pages/GoCompany' })
.catch((err: BusinessError) => {
hilog.error(0x0000, 'testTag',
`Failed to push url. Code is ${err.code}, message is ${err.message}`);
});
} else if (shortCutKey === 'HousePage') {
router.pushUrl({ url: 'pages/GoHouse' })
.catch((err: BusinessError) => {
hilog.error(0x0000, 'testTag',
`Failed to push url. Code is ${err.code}, message is ${err.message}`);
});
}
}
}
3.2 关键机制深度解析
3.2.1 冷启动与热启动的处理
当用户点击桌面快捷方式时,系统会根据应用状态采用不同的启动方式:
-
冷启动(应用未运行):系统创建新的应用实例,意图通过
onCreate()方法传递 -
热启动(应用已在后台):系统唤醒已有的应用实例,意图通过
onNewWant()方法传递
因此,必须在 onCreate() 和 onNewWant() 两个生命周期方法中都处理跳转逻辑,才能确保无论应用处于何种状态都能正确跳转。
3.2.2 参数传递机制
快捷方式通过 wants 中的 parameters 字段传递自定义参数:
json
"parameters": {
"shortCutKey": "CompanyPage"
}
在 EntryAbility 中通过 want.parameters?.shortCutKey 获取参数值。
注意:系统不会自动处理
parameters中的参数来实现页面跳转。开发者必须在 UIAbility 中主动解析参数并执行跳转逻辑。
3.2.3 四要素完整性检查
每个快捷方式必须包含完整的四要素:
-
shortcutId:必填,唯一标识 -
label:必填,显示文本 -
icon:必填,图标资源 -
wants:必填,跳转配置
任何一项缺失或配置错误都可能导致快捷方式不显示或无法跳转。
3.3 完整项目结构
text
entry/src/main/ ├── ets/ │ ├── entryability/ │ │ └── EntryAbility.ets # 跳转逻辑 │ └── pages/ │ ├── Index.ets # 主页面 │ ├── GoHouse.ets # 回家页面 │ └── GoCompany.ets # 去公司页面 ├── resources/ │ └── base/ │ ├── element/ │ │ └── string.json # 多语言字符串 │ ├── media/ │ │ ├── company.png # 公司图标 │ │ └── house.png # 回家图标 │ └── profile/ │ ├── main_pages.json # 页面路由配置 │ └── shortcuts_config.json # 快捷方式配置 └── module.json5 # 模块配置(关联快捷方式)
四、动态快捷方式:运行时添加与管理
动态快捷方式允许应用在运行时通过代码添加、更新或删除快捷方式。
4.1 权限声明
动态添加快捷方式需要在 module.json5 中声明权限:
json
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.INSTALL_SHORTCUT"
}
]
}
}
4.2 ShortcutManager API 概览
ShortcutManager 是管理系统快捷方式的核心 API:
| 方法 | 说明 |
|---|---|
addDesktopShortcutInfo(shortcutInfo, userId) |
为指定用户添加快捷方式 |
updateShortcutInfo(shortcutInfo) |
更新快捷方式信息 |
removeDesktopShortcutInfo(shortcutId, userId) |
删除指定快捷方式 |
getDesktopShortcutInfos(userId) |
查询用户的快捷方式列表 |
注意:
ShortcutManager相关 API 属于系统 API(System API),部分功能可能受系统权限限制。
4.3 动态添加快捷方式实现
步骤一:创建 ShortcutInfo 对象
typescript
import shortcutManager from '@ohos.shortcutManager';
import Want from '@ohos.app.ability.Want';
// 创建快捷方式信息
let shortcutInfo: shortcutManager.ShortcutInfo = {
shortcutId: 'dynamic_shortcut_1',
label: '我的收藏',
icon: $media.favorite_icon, // 图标资源
wants: [
{
bundleName: 'com.example.myapp',
moduleName: 'entry',
abilityName: 'EntryAbility',
parameters: {
shortCutKey: 'FavoritePage',
userId: '12345'
}
}
]
};
步骤二:调用 API 添加
typescript
import shortcutManager from '@ohos.shortcutManager';
import { BusinessError } from '@ohos.base';
try {
// userId 为 0 表示当前用户
await shortcutManager.addDesktopShortcutInfo(shortcutInfo, 0);
hilog.info(0x0000, 'testTag', 'Shortcut added successfully');
} catch (err) {
let error = err as BusinessError;
hilog.error(0x0000, 'testTag',
`Failed to add shortcut. Code: ${error.code}, message: ${error.message}`);
}
步骤三:完整工具类封装
typescript
// ShortcutsUtils.ets
import shortcutManager from '@ohos.shortcutManager';
import { BusinessError } from '@ohos.base';
import Want from '@ohos.app.ability.Want';
import hilog from '@ohos.hilog';
export class ShortcutsUtils {
private static readonly TAG: string = 'ShortcutsUtils';
/**
* 动态添加快捷方式
* @param shortcutId 快捷方式唯一ID
* @param label 显示标签
* @param icon 图标资源
* @param params 自定义参数
*/
static async addShortcut(
shortcutId: string,
label: string,
icon: Resource,
params: Record<string, string>
): Promise<boolean> {
try {
const shortcutInfo: shortcutManager.ShortcutInfo = {
shortcutId: shortcutId,
label: label,
icon: icon,
wants: [
{
bundleName: 'com.example.myapp',
moduleName: 'entry',
abilityName: 'EntryAbility',
parameters: params
}
]
};
await shortcutManager.addDesktopShortcutInfo(shortcutInfo, 0);
hilog.info(0x0000, this.TAG, `Add shortcut success: ${shortcutId}`);
return true;
} catch (err) {
let error = err as BusinessError;
hilog.error(0x0000, this.TAG,
`Add shortcut failed: ${error.code}, ${error.message}`);
return false;
}
}
/**
* 删除快捷方式
*/
static async removeShortcut(shortcutId: string): Promise<boolean> {
try {
await shortcutManager.removeDesktopShortcutInfo(shortcutId, 0);
hilog.info(0x0000, this.TAG, `Remove shortcut success: ${shortcutId}`);
return true;
} catch (err) {
let error = err as BusinessError;
hilog.error(0x0000, this.TAG,
`Remove shortcut failed: ${error.code}, ${error.message}`);
return false;
}
}
/**
* 查询所有快捷方式
*/
static async getShortcuts(): Promise<shortcutManager.ShortcutInfo[]> {
try {
const shortcuts = await shortcutManager.getDesktopShortcutInfos(0);
hilog.info(0x0000, this.TAG, `Get shortcuts count: ${shortcuts.length}`);
return shortcuts;
} catch (err) {
let error = err as BusinessError;
hilog.error(0x0000, this.TAG,
`Get shortcuts failed: ${error.code}, ${error.message}`);
return [];
}
}
}
步骤四:在业务代码中调用
typescript
// 在页面中动态添加快捷方式
import { ShortcutsUtils } from '../utils/ShortcutsUtils';
@Entry
@Component
struct SettingsPage {
async addFavoriteShortcut() {
const success = await ShortcutsUtils.addShortcut(
'favorite_page',
'我的收藏',
$media.favorite_icon,
{ shortCutKey: 'FavoritePage', source: 'settings' }
);
if (success) {
prompt.showToast({ message: '快捷方式添加成功' });
} else {
prompt.showToast({ message: '快捷方式添加失败' });
}
}
async removeFavoriteShortcut() {
const success = await ShortcutsUtils.removeShortcut('favorite_page');
if (success) {
prompt.showToast({ message: '快捷方式已移除' });
}
}
build() {
Column() {
Button('添加"我的收藏"快捷方式')
.onClick(() => this.addFavoriteShortcut())
Button('移除"我的收藏"快捷方式')
.onClick(() => this.removeFavoriteShortcut())
}
}
}
4.4 动态更新快捷方式
typescript
static async updateShortcut(
shortcutId: string,
newLabel: string,
newIcon?: Resource
): Promise<boolean> {
try {
// 先获取现有快捷方式
const shortcuts = await shortcutManager.getDesktopShortcutInfos(0);
const target = shortcuts.find(item => item.shortcutId === shortcutId);
if (!target) {
hilog.warn(0x0000, this.TAG, `Shortcut not found: ${shortcutId}`);
return false;
}
// 更新信息
target.label = newLabel;
if (newIcon) {
target.icon = newIcon;
}
// 注意:具体更新 API 取决于系统版本支持情况
// 部分版本可能需要先删除再添加
await shortcutManager.removeDesktopShortcutInfo(shortcutId, 0);
await shortcutManager.addDesktopShortcutInfo(target, 0);
hilog.info(0x0000, this.TAG, `Update shortcut success: ${shortcutId}`);
return true;
} catch (err) {
let error = err as BusinessError;
hilog.error(0x0000, this.TAG,
`Update shortcut failed: ${error.code}, ${error.message}`);
return false;
}
}
4.5 动态快捷方式的限制说明
关于 HarmonyOS NEXT 中动态快捷方式的能力,存在一些需要了解的限制:
-
部分版本限制:在某些 HarmonyOS NEXT 版本中,ShortcutManager API 仅支持静态配置的显示控制,无法真正动态增删快捷方式。这是基于系统安全性和稳定性考虑的设计选择。
-
图标和标签的静态性:shortcuts 的 label 和 icon 通常通过资源文件获取,在应用开发和打包阶段就已确定,不支持在运行过程中动态变更。
-
系统 API 权限:部分 ShortcutManager API 属于系统 API,普通第三方应用可能无法使用全部功能。
-
替代方案:对于需要用户自定义快捷菜单的场景,建议通过应用内实现替代方案。
五、多语言与图标优化
5.1 多语言适配
在 resources/base/element/string.json 中配置多语言标签:
json
{
"string": [
{
"name": "Go_to_the_Company",
"value": "去公司"
},
{
"name": "Go_to_House",
"value": "回家"
}
]
}
不同语言目录下配置对应的翻译:
-
resources/zh_CN/element/string.json:中文 -
resources/en_US/element/string.json:英文 -
resources/ja_JP/element/string.json:日文
5.2 图标优化建议
-
尺寸建议:推荐使用 512x512 像素的 PNG 格式
-
暗色模式:适配暗色模式的双套图标方案
-
背景处理:避免透明背景导致显示异常
-
资源引用:在配置中使用
$media:icon_name引用图标资源
六、避坑指南与常见问题
6.1 快捷方式不显示
检查清单:
-
是否超过 4 个快捷方式限制
-
图标资源路径是否正确
-
module.json5注册声明是否完整 -
metadata的name是否为"ohos.ability.shortcuts" -
resource路径是否正确指向配置文件
6.2 页面跳转异常
常见原因:
-
目标页面未添加
@Entry装饰器 -
路由路径拼写错误
-
未在
main_pages.json中注册页面
6.3 参数传递失败
调试技巧:
-
在
onCreate()和onNewWant()中打印want.parameters内容 -
确认
shortCutKey参数名与配置文件中一致 -
检查参数值是否在跳转逻辑中正确匹配
6.4 冷启动无法跳转
问题:点击快捷方式后,应用正常启动但停留在首页,未跳转到目标页面。
原因:仅在 onNewWant() 中处理了跳转逻辑,遗漏了 onCreate() 的处理。
解决方案:在 onCreate() 和 onNewWant() 两个方法中都调用跳转方法。
6.5 快捷方式数量限制
目前系统限制桌面展示的快捷方式最多为 4 个。如果配置了超过 4 个,超出部分会被直接忽略。
6.6 多 HAP 包场景
本文基于单 HAP 包场景进行讲解,多 HAP 包的配置逻辑一致。只需在对应的 HAP 模块中分别配置 shortcuts_config.json 和 module.json5 即可。
七、架构设计与最佳实践
7.1 与卡片功能的对比
| 对比维度 | 快捷方式(Shortcuts) | 服务卡片(Widget) |
|---|---|---|
| 交互方式 | 点击跳转至应用内页面 | 可交互,显示实时信息 |
| 展示位置 | 长按应用图标弹出 | 桌面独立显示 |
| 内容更新 | 静态或有限动态 | 支持实时数据更新 |
| 开发复杂度 | 较低 | 较高 |
7.2 安全性设计
-
参数传递仅支持字符串类型
-
系统级权限控制快捷方式创建
-
自动过滤非法字符注入
7.3 最佳实践建议
-
合理规划快捷方式数量:控制在 4 个以内,优先展示最高频的功能
-
参数命名规范:使用有意义的参数名(如
shortCutKey),便于维护 -
跳转逻辑封装:将跳转逻辑抽离为公共方法,在
onCreate和onNewWant中复用 -
错误处理完善:添加
try-catch和日志记录,便于问题排查 -
图标资源规范:使用高清图标,适配暗色模式
-
多语言支持:使用资源索引而非硬编码字符串
7.4 代码架构建议
text
entry/src/main/ets/
├── entryability/
│ └── EntryAbility.ets # 入口,负责接收Want并路由
├── pages/
│ ├── Index.ets # 首页
│ ├── GoHouse.ets # 具体功能页
│ └── GoCompany.ets
├── utils/
│ └── ShortcutsUtils.ets # 快捷方式工具类(动态添加)
└── constants/
└── ShortcutConstants.ets # 常量定义(shortCutKey等)
八、总结与展望
8.1 核心要点回顾
-
静态快捷方式:通过
shortcuts_config.json配置 +module.json5注册 +EntryAbility跳转 -
动态快捷方式:通过
ShortcutManagerAPI 在运行时添加/删除/更新 -
四要素:每个快捷方式必须包含
shortcutId、label、icon、wants -
生命周期处理:必须在
onCreate()和onNewWant()中都处理跳转逻辑 -
数量限制:最多 4 个快捷方式
8.2 未来演进方向
随着 HarmonyOS 生态的发展,快捷方式功能可能在以下方向演进:
-
场景化智能推荐:基于用户习惯自动生成快捷方式
-
跨设备同步:手机创建的快捷方式自动同步至平板
-
动态参数支持:根据时间、位置等上下文动态调整
参考资料:
华为开发者联盟官方文档
HarmonyOS 桌面快捷功能开发指南
HarmonyOS 6 静态和动态添加应用快捷方式详解
创建应用静态快捷方式典型场景开发指导
更多推荐

所有评论(0)