前段时间接了个穿戴设备的小项目,帮朋友把一款心率监测应用适配到了华为手表上。之前一直做手机和平板开发,对穿戴设备的开发模式完全陌生,花了三天时间才把环境搭好、模拟器跑起来。中间踩了不少坑,也整理出了一套完整的开发流程。今天把这份指南分享出来,希望能帮到想入门穿戴开发的同学。

一、环境搭建: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 连接

  1. 手表开启「开发者模式」:设置 → 关于手表 → 连续点击版本号 7 次
  2. 开启「USB 调试」:设置 → 系统 → 开发者选项 → USB 调试
  3. 用 USB 数据线连接电脑和手表
  4. DevEco Studio 会自动识别设备

方式二:无线调试

  1. 电脑和手表连接同一 WiFi
  2. 在手表开发者选项中查看 IP 地址
  3. 执行命令连接:
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 上架流程

穿戴应用在华为应用市场上架流程和手机应用类似:

  1. 登录华为开发者联盟
  2. 创建「穿戴」类型应用
  3. 上传签名好的 .hap 文件
  4. 填写应用信息、截图、隐私政策
  5. 提交审核(通常 1-3 天)

六、写在最后

穿戴设备的开发比手机简单很多,但也有不少专属的注意事项。最核心的区别在于:穿戴应用的交互必须极简,用户抬手看表的时间不会超过 5 秒。所以表盘设计、信息密度、操作路径都要围绕「快」和「简」来做。

这份指南涵盖了从环境搭建到发布上线的完整流程,希望能帮到想入门穿戴开发的同学。如果你在开发过程中遇到什么问题,评论区一起交流。


Logo

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

更多推荐