# 鸿蒙服务卡片实战:为新华字典应用添加桌面快捷查询卡片
## 一、前言
HarmonyOS 服务卡片(Service Widget)是鸿蒙系统的一大特色功能,它允许应用以卡片形式展示在桌面上,用户无需打开应用即可获取关键信息或快速执行操作。
在上篇文章中,我们实现了一款完整的新华字典鸿蒙应用。本文将继续深入,为应用添加服务卡片支持,使用户可以在桌面直接点击卡片打开字典查询。
---
## 二、服务卡片基础知识
### 2.1 什么是服务卡片
服务卡片是 HarmonyOS 提供的桌面 UI 组件,它本质上是一个轻量级的应用界面,运行在独立的进程中,通过 **FormExtensionAbility** 管理生命周期。
### 2.2 卡片类型
HarmonyOS 的服务卡片分为两种类型:
| 类型 | 交互方式 | 更新方式 | 适用场景 |
|------|---------|---------|---------|
| **静态卡片** | `FormLink` 组件 | 不可动态更新 | 信息展示、快捷入口 |
| **动态卡片** | `postCardAction()` 函数 | 支持定时/事件更新 | 实时信息、动态内容 |
> **关键区别**:静态卡片只能用 `FormLink` 实现点击交互,而动态卡片需要使用 `postCardAction()`。
在本文中,我们实现的是**动态卡片**,因为它支持定时更新数据和更灵活的交互。
### 2.3 卡片生命周期
```
创建 (onAddForm) → 可见 (onChangeFormVisibility)
→ 更新 (onUpdateForm) → 不可见 → 销毁 (onRemoveForm)
```
---
## 三、开发环境
| 工具 | 版本 |
|------|-----------------|
| OpenHarmony SDK | 23(API 23) |
| Hvigor | 6.24.2 |
| HDC | 3.2.0d |
| 目标设备 | HarmonyOS 6.1.0 |
| 开发语言 | ArkTS |
| UI 框架 | ArkUI |
---
## 四、卡片架构设计
### 4.1 整体架构
```
┌─────────────────────────────────────┐
│ 桌面卡片展示 │
│ ┌─────────────────────────────────┐ │
│ │ 📖 新华字典 │ │
│ │ 查字典 │ │
│ │ 点击打开应用 │ │
│ └─────────────────────────────────┘ │
│ ↓ onClick │
│ postCardAction('router') │
│ ↓ │
│ EntryAbility 启动 │
└─────────────────────────────────────┘
```
### 4.2 文件结构
```
entry/src/main/ets/form/
├── FormAbility.ets # FormExtensionAbility(卡片生命周期管理)
└── FormWidget.ets # 卡片页面 UI(ArkUI 组件)
entry/src/main/resources/base/profile/
└── form_config.json # 卡片配置(尺寸、更新策略等)
```
---
## 五、实现步骤
### 5.1 创建卡片配置文件
首先在 `resources/base/profile/` 下创建 `form_config.json`,描述卡片的元数据:
```json
{
"forms": [
{
"name": "DictionaryForm",
"displayName": "新华字典",
"description": "快速查询汉字释义",
"src": "./ets/form/FormWidget.ets",
"uiSyntax": "arkts",
"window": {
"designWidth": 120,
"autoDesignWidth": true
},
"colorMode": "auto",
"formConfigAbility": "ability://com.nutpi.myapplication/EntryAbility",
"formVisibleNotify": true,
"isDefault": true,
"updateEnabled": true,
"scheduledUpdateTime": "10:00",
"updateDuration": 0,
"defaultDimension": "1*2",
"supportDimensions": ["1*2", "2*2"]
}
]
}
```
**关键字段说明:**
| 字段 | 值 | 说明 |
|------|-----|------|
| `uiSyntax` | `"arkts"` | 使用 ArkTS 开发卡片 UI |
| `formVisibleNotify` | `true` | 开启可见性通知(动态卡片) |
| `updateEnabled` | `true` | 允许定时更新 |
| `supportDimensions` | `["1*2", "2*2"]` | 支持的尺寸规格 |
| `defaultDimension` | `"1*2"` | 默认尺寸 |
### 5.2 实现 FormExtensionAbility
FormExtensionAbility 是卡片的后端逻辑,管理卡片的生命周期:
```typescript
import { FormExtensionAbility, formBindingData, formInfo } from '@kit.FormKit';
import { Want } from '@kit.AbilityKit';
export default class DictionaryFormAbility extends FormExtensionAbility {
/**
* 卡片被创建时调用,返回卡片初始数据
*/
onAddForm(want: Want): formBindingData.FormBindingData {
const formData: Record<string, Object> = {
'word': '好',
'pinyin': 'hǎo',
'radical': '女',
'strokes': '6',
'formHint': '点击打开新华字典',
};
return formBindingData.createFormBindingData(formData);
}
/**
* 卡片更新时调用(定时更新或主动刷新)
*/
onUpdateForm(formId: string): void {
// 可以在这里从网络获取最新数据并更新卡片
}
/**
* 卡片可见性变化时调用
*/
onChangeFormVisibility(newStatus: Record<string, number>): void {
// 可见时刷新数据,不可见时释放资源
}
/**
* 卡片被销毁时调用
*/
onRemoveForm(formId: string): void {
// 清理资源
}
/**
* 卡片消息事件处理
*/
onFormEvent(formId: string, message: string): void {
// 处理来自卡片的消息事件
}
}
```
**生命周期方法调用时机:**
| 方法 | 调用时机 |
|------|---------|
| `onAddForm` | 用户将卡片添加到桌面时 |
| `onUpdateForm` | 达到定时更新间隔时 |
| `onChangeFormVisibility` | 卡片在桌面可见/不可见时 |
| `onRemoveForm` | 用户从桌面移除卡片时 |
| `onFormEvent` | 卡片内触发 message 事件时 |
### 5.3 实现卡片 UI
卡片页面是一个普通的 ArkUI 组件,用 `@Entry` 和 `@Component` 装饰:
```typescript
@Entry
@Component
struct DictionaryForm {
build() {
Column() {
// 标题区域
Row() {
Text('📖').fontSize(20).margin({ right: 6 })
Text('新华字典')
.fontSize(16)
.fontWeight(FontWeight.Bold)
.fontColor('#1a1a2e')
}
.margin({ bottom: 8 })
// 汉字展示
Text('查字典')
.fontSize(40)
.fontWeight(FontWeight.Bold)
.fontColor('#4a6cf7')
.margin({ bottom: 4 })
// 子标题
Text('点击打开应用')
.fontSize(10)
.fontColor('#bbb')
.margin({ top: 6 })
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
.padding(12)
// 点击跳转到主应用
.onClick(() => {
postCardAction(this, {
action: 'router',
abilityName: 'EntryAbility',
params: {}
});
})
}
}
```
**关键实现细节:**
1. **`postCardAction()`**:这是动态卡片中的全局函数,用于触发交互动作。它有以下几个 action 类型:
- `"router"`:跳转到指定 UIAbility
- `"message"`:发送消息到 FormExtensionAbility 的 `onFormEvent`
- `"call"`:在后台启动 UIAbility
2. **`this` 上下文**:`postCardAction` 的第一个参数是当前组件的 `this` 上下文。
### 5.4 注册卡片到模块配置
在 `module.json5` 中注册 FormExtensionAbility:
```json5
{
"extensionAbilities": [
{
"name": "DictionaryFormAbility",
"srcEntry": "./ets/form/FormAbility.ets",
"label": "$string:EntryAbility_label",
"description": "新华字典服务卡片",
"type": "form",
"exported": true,
"metadata": [
{
"name": "ohos.extension.form",
"resource": "$profile:form_config"
}
]
}
]
}
```
**重要参数:**
| 参数 | 说明 |
|------|------|
| `type: "form"` | 声明此 ExtensionAbility 是服务卡片类型 |
| `metadata` | 引用 `ohos.extension.form` 类型,指向卡片配置 |
---
## 六、FormLink vs postCardAction
这是开发中最容易踩坑的地方,必须根据卡片类型选择正确的交互方式:
| | 静态卡片 | 动态卡片 |
|------|---------|---------|
| **配置特征** | `updateEnabled: false` | `updateEnabled: true` 或 `formVisibleNotify: true` |
| **交互方式** | `FormLink` 组件 | `postCardAction()` 函数 |
| **数据更新** | 不支持运行时更新 | 支持定时/事件更新 |
| **适用场景** | 简单信息展示 | 实时数据展示 |
**区分方法:** 只要 `form_config.json` 中设置了 `updateEnabled: true` 或 `formVisibleNotify: true`,卡片就是动态的,必须使用 `postCardAction`。
如果使用了错误的交互方式,点击卡片将没有任何反应。
---
## 七、遇到的坑与解决方案
### 坑 1:FormLink 点击无反应
**现象**:使用 `FormLink` 组件包裹卡片内容后,点击卡片没有任何跳转
**原因**:卡片配置了 `formVisibleNotify: true`,被识别为**动态卡片**,但 `FormLink` 只适用于**静态卡片**
**解决**:将 `FormLink` 替换为 `Column.onClick` + `postCardAction()`
```typescript
// ❌ 静态卡片方式(动态卡片不生效)
FormLink({ action: 'router', abilityName: 'EntryAbility', params: {} }) {
// 卡片内容
}
// ✅ 动态卡片方式
Column() {
// 卡片内容
}
.onClick(() => {
postCardAction(this, {
action: 'router',
abilityName: 'EntryAbility',
params: {}
});
})
```
### 坑 2:卡片配置 Schema 校验失败
**现象**:构建时 hvigor 报错 `must have required property 'updateEnabled'`
**原因**:卡片配置缺少 `updateEnabled` 字段,这是必填项
**解决**:在 `form_config.json` 中添加 `"updateEnabled": true`
### 坑 3:@Entry 缺少参数警告
**现象**:编译警告 `@Entry should have a parameter, like '@Entry (storage)'`
**原因**:卡片页面中 `@Entry` 装饰器缺少 `LocalStorage` 参数
**解决**:对于不需要 LocalStorage 的简单卡片,可以忽略此警告;如果需要在卡片中使用状态数据,可以添加 `@Entry({ storage: formStorage })`。
---
## 八、构建与部署
### 8.1 构建
```bash
hvigorw assembleHap --mode module -p product=default -p buildMode=debug
```
### 8.2 安装
```bash
hdc install entry/build/default/outputs/default/entry-default-signed.hap
```
### 8.3 在桌面添加卡片
安装后,在设备桌面操作:
1. 长按桌面空白区域
2. 选择「服务卡片」
3. 找到「新华字典」
4. 点击添加到桌面
---
## 九、项目心得
1. **卡片类型决定交互方式**:开发前需要先明确卡片是静态还是动态,选错交互方式会导致功能失效。
2. **卡片 UI 受限制**:服务卡片只支持有限的 ArkUI 组件(Column、Row、Text、Image、Button 等),不支持 Scroll、List 等复杂组件。设计卡片 UI 时需要注意这一点。
3. **Card dimensions**:卡片尺寸使用网格单位(1×2、2×2、2×4 等),设计时要考虑不同尺寸下的布局适配。
4. **动态更新机制**:动态卡片可以通过 `onUpdateForm` 定时更新数据,也可以通过 `formProvider` 主动推送更新。
5. **postCardAction 的三种 action**:
- `router`:最常用,用户点击后跳转到应用
- `message`:通过 `onFormEvent` 回调处理,适合不需要打开应用的轻量操作
- `call`:后台启动,适合执行不需要界面的任务
---
## 十、总结
本文详细介绍了为鸿蒙新华字典应用添加服务卡片的完整过程,从卡片配置、生命周期管理、UI 实现到交互处理。
核心要点:
- 动态卡片用 `postCardAction`,静态卡片用 `FormLink`
- `form_config.json` 中 `updateEnabled` 和 `formVisibleNotify` 决定卡片类型
- `FormExtensionAbility` 管理卡片生命周期
- 卡片 UI 受限于有限的 ArkUI 组件集
---
## 项目地址
本文所有代码已开源:[https://gitcode.com/jianguoxu/myapplication](https://gitcode.com/jianguoxu/myapplication)
鸿蒙服务卡片实战:为新华字典应用添加桌面快捷查询卡片
不爱吃糖的程序媛2026-06-09 21:14
相关推荐
Davina_yu3 小时前
弹窗交互:AlertDialog与CustomDialog的创建与关闭(11)90后的晨仔3 小时前
HarmonyOS 锁屏音频播放完整实践指南90后的晨仔3 小时前
鸿蒙应用动态桌面图标功能实现完全指南nashane4 小时前
HarmonyOS 6学习:JsCrash“闪退”法医指南——从FaultLog堆栈还原崩溃现场的终极手册李二。5 小时前
鸿蒙OS NEXT 批量重命名工具:PC端文件管理的效率革命HwJack206 小时前
鸿蒙背景下 Cocos Creator 的三大 JS 引擎:JIT 与热更新的十字路口提子拌饭1336 小时前
Column 嵌套布局:多级 Column 实现复杂纵向结构——鸿蒙 HarmonyOS ArkTS 原生学习应用前端不太难8 小时前
鸿蒙 App 分布式数据同步:架构设计 + Demo 实现