一、前言

在功能日益复杂的应用中,用户往往需要多步操作才能找到常用功能。而应用快捷方式能让用户一键直达核心功能,既提升操作效率,也能增强用户对应用的粘性。想象一下,每天下班都要打开地图 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 技术实现原理

快捷方式的实现遵循 "配置即生成" 的设计理念,其核心链路可分解为:

  1. 配置声明:通过 JSON 文件定义快捷方式元数据(shortcutId、label、icon、wants)

  2. 系统注册:在应用配置清单(module.json5)中声明快捷方式资源

  3. 动态路由: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 中动态快捷方式的能力,存在一些需要了解的限制:

  1. 部分版本限制:在某些 HarmonyOS NEXT 版本中,ShortcutManager API 仅支持静态配置的显示控制,无法真正动态增删快捷方式。这是基于系统安全性和稳定性考虑的设计选择。

  2. 图标和标签的静态性:shortcuts 的 label 和 icon 通常通过资源文件获取,在应用开发和打包阶段就已确定,不支持在运行过程中动态变更。

  3. 系统 API 权限:部分 ShortcutManager API 属于系统 API,普通第三方应用可能无法使用全部功能。

  4. 替代方案:对于需要用户自定义快捷菜单的场景,建议通过应用内实现替代方案。


五、多语言与图标优化

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 图标优化建议

  1. 尺寸建议:推荐使用 512x512 像素的 PNG 格式

  2. 暗色模式:适配暗色模式的双套图标方案

  3. 背景处理:避免透明背景导致显示异常

  4. 资源引用:在配置中使用 $media:icon_name 引用图标资源


六、避坑指南与常见问题

6.1 快捷方式不显示

检查清单

  1. 是否超过 4 个快捷方式限制

  2. 图标资源路径是否正确

  3. module.json5 注册声明是否完整

  4. metadata 的 name 是否为 "ohos.ability.shortcuts"

  5. resource 路径是否正确指向配置文件

6.2 页面跳转异常

常见原因

  1. 目标页面未添加 @Entry 装饰器

  2. 路由路径拼写错误

  3. 未在 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 安全性设计

  1. 参数传递仅支持字符串类型

  2. 系统级权限控制快捷方式创建

  3. 自动过滤非法字符注入

7.3 最佳实践建议

  1. 合理规划快捷方式数量:控制在 4 个以内,优先展示最高频的功能

  2. 参数命名规范:使用有意义的参数名(如 shortCutKey),便于维护

  3. 跳转逻辑封装:将跳转逻辑抽离为公共方法,在 onCreate 和 onNewWant 中复用

  4. 错误处理完善:添加 try-catch 和日志记录,便于问题排查

  5. 图标资源规范:使用高清图标,适配暗色模式

  6. 多语言支持:使用资源索引而非硬编码字符串

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 核心要点回顾

  1. 静态快捷方式:通过 shortcuts_config.json 配置 + module.json5 注册 + EntryAbility 跳转

  2. 动态快捷方式:通过 ShortcutManager API 在运行时添加/删除/更新

  3. 四要素:每个快捷方式必须包含 shortcutIdlabeliconwants

  4. 生命周期处理:必须在 onCreate() 和 onNewWant() 中都处理跳转逻辑

  5. 数量限制:最多 4 个快捷方式

8.2 未来演进方向

随着 HarmonyOS 生态的发展,快捷方式功能可能在以下方向演进:

  1. 场景化智能推荐:基于用户习惯自动生成快捷方式

  2. 跨设备同步:手机创建的快捷方式自动同步至平板

  3. 动态参数支持:根据时间、位置等上下文动态调整


参考资料

  • 华为开发者联盟官方文档

  • HarmonyOS 桌面快捷功能开发指南

  • HarmonyOS 6 静态和动态添加应用快捷方式详解

  • 创建应用静态快捷方式典型场景开发指导

Logo

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

更多推荐