HarmonyOS 5.0 穿戴设备开发完整指南:从环境搭建到应用发布
前段时间接了个穿戴设备的小项目,帮朋友把一款心率监测应用适配到了华为手表上。之前一直做手机和平板开发,对穿戴设备的开发模式完全陌生,花了三天时间才把环境搭好、模拟器跑起来。中间踩了不少坑,也整理出了一套完整的开发流程。今天把这份指南分享出来,希望能帮到想入门穿戴开发的同学。
一、环境搭建:30分钟跑通第一个应用
穿戴开发和手机开发的环境基本一致,但有几个细节需要注意。
1.1 DevEco Studio 配置
首先确认 DevEco Studio 版本在 4.0 以上,这个版本才完整支持 HarmonyOS 5.0 的穿戴特性。然后打开 SDK Manager,勾选穿戴相关的 SDK 组件:
| SDK 组件 | 说明 | 必须安装 |
|---|---|---|
| HarmonyOS SDK 5.0.0 | 核心开发包 | 是 |
| Wearable SDK | 穿戴设备专用 API | 是 |
| Wearable Emulator | 穿戴模拟器镜像 | 是 |
| Wearable Device Tool | 真机调试工具 | 建议 |
1.2 创建穿戴项目
新建项目时选择「穿戴设备」模板,注意项目的 module 类型必须是 wearable,target device 选择「手表」。
项目结构和手机应用类似,但会自动生成穿戴专用的资源目录:
entry/
src/
main/
ets/ 代码目录
resources/
base/
media/ 表盘背景图
element/ 颜色、尺寸定义
profile/ 表盘配置
wearable/ 穿戴专用资源
1.3 启动模拟器调试
在 Device Manager 里启动一个穿戴模拟器,推荐用 46mm 表盘尺寸,覆盖率最高。启动后点击 Run 按钮,第一个穿戴应用就能跑起来了。
小技巧:穿戴模拟器可以用电脑键盘控制方向键,比鼠标点方便多了。
二、穿戴设备核心 API 速查
穿戴应用的 API 和手机版有差异,以下是开发时最常用的几个模块。
2.1 传感器数据采集
心率、步数、卡路里等健康数据通过 @kit.SensorKit 模块获取:
import { sensor } from '@kit.SensorKit';
const heartRateSensor = sensor.getSingleSensor(sensor.SensorType.SENSOR_TYPE_HEART_RATE);
sensor.on(sensor.SensorType.SENSOR_TYPE_HEART_RATE, (data: sensor.SensorData) => {
const heartRate = data.values[0];
console.info(`当前心率: ${heartRate} BPM`);
if (heartRate > 120) {
this.triggerAlert('心率过高,请注意休息');
}
});
sensor.start(heartRateSensor);
常用传感器类型对照表:
| 传感器 | 类型常量 | 数据说明 |
|---|---|---|
| 心率 | SENSOR_TYPE_HEART_RATE | values[0]: BPM |
| 步数 | SENSOR_TYPE_STEP_COUNTER | values[0]: 累计步数 |
| 卡路里 | SENSOR_TYPE_CALORIES | values[0]: 千卡路里 |
| 距离 | SENSOR_TYPE_DISTANCE | values[0]: 米 |
| 血氧 | SENSOR_TYPE_SPO2 | values[0]: 百分比 |
2.2 表盘开发
表盘是穿戴应用的核心入口,通过 WatchFace 组件开发:
@Entry
@Component
struct WatchFace {
@State currentTime: string = '';
@State heartRate: number = 72;
aboutToAppear() {
this.startTimeUpdate();
this.startHeartRateMonitor();
}
build() {
Stack() {
Image($r('app.media.watch_background'))
.width('100%')
.height('100%')
Column() {
Text(this.currentTime)
.fontSize(32)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
Text(`${this.heartRate} BPM`)
.fontSize(14)
.fontColor('#FF6B6B')
.margin({ top: 8 })
}
.justifyContent(FlexAlign.Center)
}
.width('100%')
.height('100%')
.onClick(() => {
router.pushUrl({ url: 'pages/DetailPage' });
})
}
private startTimeUpdate() {
setInterval(() => {
const now = new Date();
this.currentTime = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}`;
}, 1000);
}
private startHeartRateMonitor() {
sensor.on(sensor.SensorType.SENSOR_TYPE_HEART_RATE, (data: sensor.SensorData) => {
this.heartRate = Math.round(data.values[0]);
});
}
}
2.3 通知推送
穿戴设备可以接收来自手机的通知,也可以主动发送本地通知:
import { notificationManager } from '@kit.NotificationKit';
async function sendWearableNotification(title: string, content: string) {
const notification: notificationManager.NotificationRequest = {
id: Date.now(),
content: {
notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
normal: {
title: title,
text: content
}
},
deliveryTime: new Date().getTime(),
slotType: notificationManager.SlotType.IMPORTANT
};
await notificationManager.publish(notification);
}
2.4 设备互联
穿戴设备可以和手机、平板等设备互联,实现数据同步:
import { distributedKVStore } from '@kit.DistributedKVStoreKit';
const kvStore = distributedKVStore.createKVStoreManager({
name: 'health_data',
securityLevel: distributedKVStore.SecurityLevel.S3
});
async function syncHealthData(healthData: HealthData) {
await kvStore.put('latest_record', JSON.stringify(healthData));
console.info('健康数据已同步到其他设备');
}
三、实战案例:简易心率监测应用
我们来实现一个完整的穿戴应用,功能包括:实时心率显示、异常告警、数据记录。
3.1 页面结构
pages/
WatchFace.ets 主表盘页面
DetailPage.ets 详细数据页面
HistoryPage.ets 历史记录页面
3.2 完整代码
先创建一个工具类来管理心率数据:
// utils/HeartRateManager.ets
export class HeartRateManager {
private static instance: HeartRateManager;
private records: HeartRateRecord[] = [];
static getInstance(): HeartRateManager {
if (!HeartRateManager.instance) {
HeartRateManager.instance = new HeartRateManager();
}
return HeartRateManager.instance;
}
addRecord(bpm: number) {
const record: HeartRateRecord = {
timestamp: Date.now(),
bpm: bpm
};
this.records.unshift(record);
if (this.records.length > 100) {
this.records.pop();
}
}
getRecords(): HeartRateRecord[] {
return this.records;
}
getAverage(): number {
if (this.records.length === 0) return 0;
const sum = this.records.reduce((acc, r) => acc + r.bpm, 0);
return Math.round(sum / this.records.length);
}
getMax(): number {
if (this.records.length === 0) return 0;
return Math.max(...this.records.map(r => r.bpm));
}
}
interface HeartRateRecord {
timestamp: number;
bpm: number;
}
主表盘页面:
import { HeartRateManager } from '../utils/HeartRateManager';
@Entry
@Component
struct WatchFace {
@State heartRate: number = 72;
@State isAlert: boolean = false;
private heartRateManager: HeartRateManager = HeartRateManager.getInstance();
aboutToAppear() {
this.startMonitoring();
}
aboutToDisappear() {
sensor.off(sensor.SensorType.SENSOR_TYPE_HEART_RATE);
}
build() {
Stack() {
// 背景
Circle()
.width('100%')
.height('100%')
.fill(this.isAlert ? '#FF6B6B' : '#1A1A2E')
Column() {
Text(this.heartRate.toString())
.fontSize(48)
.fontWeight(FontWeight.Bold)
.fontColor(Color.White)
Text('BPM')
.fontSize(12)
.fontColor('#AAAAAA')
.margin({ top: 4 })
if (this.isAlert) {
Text('心率异常')
.fontSize(14)
.fontColor(Color.White)
.margin({ top: 16 })
.animation({ duration: 500, iterations: Infinity })
}
}
.justifyContent(FlexAlign.Center)
}
.width('100%')
.height('100%')
.onClick(() => {
router.pushUrl({ url: 'pages/DetailPage' });
})
}
private startMonitoring() {
sensor.on(sensor.SensorType.SENSOR_TYPE_HEART_RATE, (data: sensor.SensorData) => {
const bpm = Math.round(data.values[0]);
this.heartRate = bpm;
this.heartRateManager.addRecord(bpm);
this.isAlert = bpm > 120 || bpm < 50;
if (this.isAlert) {
this.sendNotification(bpm);
}
});
}
private async sendNotification(bpm: number) {
await notificationManager.publish({
id: Date.now(),
content: {
notificationContentType: notificationManager.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
normal: {
title: '心率告警',
text: `当前心率 ${bpm} BPM,请注意休息`
}
},
slotType: notificationManager.SlotType.IMPORTANT
});
}
}
四、穿戴设备调试技巧
4.1 模拟器调试
穿戴模拟器和手机模拟器的操作有差异:
- 使用电脑键盘方向键控制,比鼠标点更精确
- 表盘旋转:Ctrl + 鼠标滚轮
- 侧边按钮:Esc 键
4.2 真机调试
真机调试有两种方式:
方式一:USB 连接
- 手表开启「开发者模式」:设置 → 关于手表 → 连续点击版本号 7 次
- 开启「USB 调试」:设置 → 系统 → 开发者选项 → USB 调试
- 用 USB 数据线连接电脑和手表
- DevEco Studio 会自动识别设备
方式二:无线调试
- 电脑和手表连接同一 WiFi
- 在手表开发者选项中查看 IP 地址
- 执行命令连接:
hdc connect <手表IP>:87101
4.3 日志分析
穿戴设备的日志和手机不同,需要用 hdc shell hilog 命令过滤:
hdc shell hilog | grep "Wearable"
hdc shell hilog | grep "Sensor"
hdc shell hilog | grep -i error
4.4 性能优化要点
穿戴设备硬件资源有限,需要特别注意:
| 优化项 | 建议 |
|---|---|
| CPU 占用 | 传感器采样间隔设为 5 秒以上 |
| 内存占用 | 图片资源压缩到 100KB 以下 |
| 电池消耗 | 后台任务用 WorkManager,不要用定时任务 |
| 网络请求 | 批量请求,减少连接次数 |
| UI 渲染 | 减少组件嵌套层级 |
五、穿戴应用发布注意事项
5.1 签名配置
穿戴应用的签名和手机应用通用,但需要在 build-profile.json5 中指定穿戴 module:
{
"app": {
"signingConfigs": [{
"name": "wearable_release",
"material": {
"storeFile": "sign/release.p12",
"storePassword": "******",
"signAlg": "SHA256",
"profile": "sign/release.p7b"
}
}]
},
"modules": [{
"name": "entry",
"targets": ["wearable"]
}]
}
5.2 上架检查清单
| 检查项 | 要求 | 状态 |
|---|---|---|
| 表盘适配 | 支持 42mm 和 46mm 两种尺寸 | ☐ |
| 权限声明 | 传感器权限注明用途 | ☐ |
| 性能指标 | 启动时间 < 3 秒 | ☐ |
| 电池消耗 | 1 小时使用耗电 < 15% | ☐ |
| 通知权限 | 默认关闭,用户主动开启 | ☐ |
| 数据隐私 | 不上传健康数据到云端 | ☐ |
| 截图素材 | 覆盖表盘、详情页、历史页 | ☐ |
5.3 上架流程
穿戴应用在华为应用市场上架流程和手机应用类似:
- 登录华为开发者联盟
- 创建「穿戴」类型应用
- 上传签名好的
.hap文件 - 填写应用信息、截图、隐私政策
- 提交审核(通常 1-3 天)
六、写在最后
穿戴设备的开发比手机简单很多,但也有不少专属的注意事项。最核心的区别在于:穿戴应用的交互必须极简,用户抬手看表的时间不会超过 5 秒。所以表盘设计、信息密度、操作路径都要围绕「快」和「简」来做。
这份指南涵盖了从环境搭建到发布上线的完整流程,希望能帮到想入门穿戴开发的同学。如果你在开发过程中遇到什么问题,评论区一起交流。
更多推荐

所有评论(0)