基于HarmonyOS 5的卡片式服务开发与跨设备同步实践

一、项目概述

本项目基于HarmonyOS 5的原子化服务新特性,开发一个支持跨设备同步的智能卡片应用,包含步数统计和日期显示功能。参考《鸿蒙跨端U同步:同一局游戏中多设备玩家昵称/头像显示》的分布式技术,实现卡片数据在多设备间的实时同步。

https://example.com/harmony-card-arch.png
图1:卡片服务架构(包含UI卡片、业务逻辑层和分布式数据同步层)

二、核心功能实现

1. 卡片配置与布局定义

卡片配置文件resources/base/profile/widget_card.json
{
  "forms": [
    {
      "name": "HealthCard",
      "description": "健康数据卡片",
      "type": "JS",
      "colorMode": "auto",
      "isDefault": true,
      "updateEnabled": true,
      "scheduledUpdateTime": "10:00",
      "updateDuration": 1,
      "defaultDimension": "2 * 2",
      "supportDimensions": ["2 * 2", "2 * 4"],
      "jsComponentName": "HealthCard",
      "formConfigAbility": "ability://MainAbility"
    }
  ]
}
卡片布局resources/base/healthcard/healthcard.hml
<div class="container">
  <div class="header">
    <text class="title">健康助手</text>
    <image src="/common/refresh.png" class="refresh" onclick="updateData"></image>
  </div>
  
  <div class="content">
    <div class="data-item">
      <text class="label">今日步数</text>
      <text class="value">{{stepCount}}</text>
      <progress class="progress" percent="{{stepPercent}}"></progress>
    </div>
    
    <div class="data-item">
      <text class="label">当前日期</text>
      <text class="value">{{currentDate}}</text>
    </div>
  </div>
  
  <div class="footer">
    <text class="device-info">来自: {{deviceName}}</text>
    <text class="update-time">更新: {{updateTime}}</text>
  </div>
</div>

2. 卡片逻辑实现(ArkTS)

主卡片逻辑HealthCard.ets
// 导入分布式数据管理模块
import distributedData from '@ohos.data.distributedData';
import deviceInfo from '@ohos.deviceInfo';

@Entry
@Component
struct HealthCard {
  @State stepCount: number = 0;
  @State stepPercent: number = 0;
  @State currentDate: string = '';
  @State updateTime: string = '';
  @State deviceName: string = deviceInfo.deviceInfo.deviceName;
  
  // 分布式数据对象
  private distObject: distributedData.DataObject;
  private stepGoal: number = 10000;
  
  aboutToAppear() {
    // 初始化分布式数据对象
    this.distObject = distributedData.create({
      steps: 0,
      lastUpdate: 0,
      sourceDevice: ''
    });
    
    // 监听数据变化
    this.distObject.on('change', (fields: string[]) => {
      if (fields.includes('steps')) {
        this.handleStepUpdate();
      }
    });
    
    this.loadData();
    this.startStepCounter();
  }
  
  // 加载数据
  private loadData() {
    // 从本地存储获取数据
    const steps = localStorage.get('stepCount') || 0;
    this.updateSteps(steps);
    this.updateDate();
  }
  
  // 开始计步
  private startStepCounter() {
    // 使用传感器API获取步数
    const sensorManager = sensor.getSensorManager();
    const stepCounter = sensorManager.getDefaultSensor(sensor.SensorId.STEP_COUNTER);
    
    stepCounter.on(sensor.SensorEvent.SENSOR_EVENT, (data: sensor.StepCounterResponse) => {
      this.updateSteps(data.steps);
      this.syncSteps(data.steps);
    });
  }
  
  // 更新步数显示
  private updateSteps(steps: number) {
    this.stepCount = steps;
    this.stepPercent = Math.min((steps / this.stepGoal) * 100, 100);
    this.updateTime = this.formatTime(Date.now());
    
    // 保存到本地
    localStorage.set('stepCount', steps);
  }
  
  // 同步步数到其他设备
  private syncSteps(steps: number) {
    this.distObject.steps = steps;
    this.distObject.lastUpdate = Date.now();
    this.distObject.sourceDevice = deviceInfo.deviceInfo.deviceId;
    
    // 获取已连接设备
    const connectedDevices = deviceManager.getConnectedDevices()
      .map(d => d.deviceId)
      .filter(id => id !== deviceInfo.deviceInfo.deviceId);
    
    if (connectedDevices.length > 0) {
      this.distObject.setDistributed(connectedDevices);
    }
  }
  
  // 处理远程步数更新
  private handleStepUpdate() {
    const remoteSteps = this.distObject.steps as number;
    const remoteDevice = this.distObject.sourceDevice as string;
    const remoteTime = this.distObject.lastUpdate as number;
    
    // 只接受来自其他设备的更新
    if (remoteDevice !== deviceInfo.deviceInfo.deviceId) {
      this.updateSteps(remoteSteps);
      this.deviceName = this.getDeviceName(remoteDevice);
      this.updateTime = this.formatTime(remoteTime);
    }
  }
  
  // 更新日期显示
  private updateDate() {
    const now = new Date();
    this.currentDate = `${now.getFullYear()}年${now.getMonth()+1}月${now.getDate()}日`;
  }
  
  // 格式化时间
  private formatTime(timestamp: number): string {
    const date = new Date(timestamp);
    return `${date.getHours()}:${date.getMinutes().toString().padStart(2, '0')}`;
  }
  
  // 获取设备名称
  private getDeviceName(deviceId: string): string {
    if (deviceId === deviceInfo.deviceInfo.deviceId) return '本机';
    
    const device = deviceManager.getDeviceInfo(deviceId);
    return device?.name || '其他设备';
  }
  
  // 手动更新数据
  @ExternalFunction
  updateData() {
    this.loadData();
    this.syncSteps(this.stepCount);
  }
  
  build() {
    Column() {
      // 卡片内容将根据HML模板渲染
    }
  }
}

3. 跨设备同步增强实现

// 分布式数据同步服务
class StepSyncService {
  private static instance: StepSyncService;
  private distObject: distributedData.DataObject;
  private listeners: Array<() => void> = [];
  
  static getInstance(): StepSyncService {
    if (!StepSyncService.instance) {
      StepSyncService.instance = new StepSyncService();
    }
    return StepSyncService.instance;
  }
  
  constructor() {
    this.distObject = distributedData.create({
      steps: 0,
      lastUpdate: 0,
      sourceDevice: '',
      deviceList: []
    });
    
    // 监听设备连接变化
    deviceManager.on('deviceStateChange', () => {
      this.updateDeviceList();
    });
    
    // 监听数据变化
    this.distObject.on('change', (fields: string[]) => {
      if (fields.includes('steps') || fields.includes('deviceList')) {
        this.notifyListeners();
      }
    });
    
    this.updateDeviceList();
  }
  
  // 更新设备列表
  private updateDeviceList() {
    const devices = deviceManager.getConnectedDevices();
    this.distObject.deviceList = devices.map(d => ({
      id: d.deviceId,
      name: d.deviceName,
      steps: 0
    }));
    
    this.distObject.setDistributed(this.getConnectedDeviceIds());
  }
  
  // 同步步数数据
  syncSteps(steps: number) {
    this.distObject.steps = steps;
    this.distObject.lastUpdate = Date.now();
    this.distObject.sourceDevice = deviceInfo.deviceInfo.deviceId;
    
    // 更新当前设备步数
    this.updateDeviceSteps(deviceInfo.deviceInfo.deviceId, steps);
    
    this.distObject.setDistributed(this.getConnectedDeviceIds());
  }
  
  // 更新设备步数
  private updateDeviceSteps(deviceId: string, steps: number) {
    const devices = this.distObject.deviceList as Array<any>;
    const index = devices.findIndex(d => d.id === deviceId);
    
    if (index >= 0) {
      devices[index].steps = steps;
      this.distObject.deviceList = [...devices];
    }
  }
  
  // 获取当前步数
  getCurrentSteps(): number {
    return this.distObject.steps as number;
  }
  
  // 获取设备列表
  getDeviceList(): Array<any> {
    return [...(this.distObject.deviceList as Array<any>)];
  }
  
  // 获取已连接设备ID
  private getConnectedDeviceIds(): string[] {
    return deviceManager.getConnectedDevices()
      .map(d => d.deviceId)
      .filter(id => id !== deviceInfo.deviceInfo.deviceId);
  }
  
  // 监听器相关代码省略...
}

三、关键功能说明

1. 卡片生命周期管理

生命周期方法 触发时机 典型用途
aboutToAppear 卡片创建或显示时 初始化数据、启动传感器
onDestroy 卡片销毁时 释放资源、停止传感器
onUpdateForm 定时更新或手动更新时 刷新卡片数据

2. 分布式数据同步流程

sequenceDiagram
    participant DeviceA
    participant DeviceB
    participant 分布式数据管理
    
    DeviceA->>DeviceA: 步数变化
    DeviceA->>分布式数据管理: 更新步数数据
    分布式数据管理->>DeviceB: 同步数据变更
    DeviceB->>DeviceB: 更新卡片显示

3. 多设备数据合并策略

// 数据合并示例
private mergeSteps(localSteps: number, remoteSteps: number): number {
  // 采用最大值策略
  return Math.max(localSteps, remoteSteps);
}

四、项目扩展与优化

1. 性能优化建议

  1. ​卡片更新策略​​:

    "updateEnabled": true,
    "scheduledUpdateTime": "10:00",
    "updateDuration": 1
  2. ​传感器使用优化​​:

    sensorManager.setInterval(sensor.SensorId.STEP_COUNTER, 600000000); // 设置10分钟间隔

2. 功能扩展建议

  1. ​多尺寸卡片支持​​:

    "supportDimensions": ["2 * 2", "2 * 4", "4 * 4"]
  2. ​健康数据分析​​:

    interface HealthReport {
      avgSteps: number;
      trend: 'up' | 'down';
      achievement: number;
    }
  3. ​交互式卡片​​:

    @ExternalFunction
    setStepGoal(newGoal: number) {
      this.stepGoal = newGoal;
    }

五、测试方案

1. 测试用例设计

测试类型 测试场景 验证点
功能测试 添加卡片到桌面 正确显示初始数据
功能测试 模拟步数变化 卡片数据实时更新
同步测试 多设备步数同步 所有设备显示相同数据
性能测试 长时间运行 内存占用稳定
兼容测试 不同设备尺寸 布局适配正常

2. 自动化测试示例

// 卡片功能测试
describe('HealthCard Tests', () => {
  let card: HealthCard;
  
  before(() => {
    card = new HealthCard();
  });
  
  it('should display current date', () => {
    const now = new Date();
    const expectedDate = `${now.getFullYear()}年${now.getMonth()+1}月${now.getDate()}日`;
    expect(card.currentDate).toBe(expectedDate);
  });
  
  it('should sync steps across devices', () => {
    const testSteps = 5000;
    const syncService = StepSyncService.getInstance();
    
    card.syncSteps(testSteps);
    expect(syncService.getCurrentSteps()).toBe(testSteps);
  });
});

六、总结

本项目基于HarmonyOS 5的原子化服务特性,实现了一个支持跨设备同步的健康数据卡片,主要特点包括:

  1. ​灵活的服务卡片​​:支持多种尺寸配置和定时更新
  2. ​实时数据同步​​:利用分布式数据管理实现多设备步数同步
  3. ​低功耗设计​​:优化传感器使用策略减少能耗
  4. ​直观的数据展示​​:清晰呈现步数和日期信息

通过参考《鸿蒙跨端U同步:同一局游戏中多设备玩家昵称/头像显示》的技术方案,我们验证了HarmonyOS 5在原子化服务和分布式能力方面的创新,为开发者提供了构建跨设备协同应用的新范式。

注意事项:
1. 实际开发中需要处理权限申请(传感器、分布式数据等)
2. 考虑不同设备的传感器精度差异
3. 生产环境需要添加更完善的错误处理机制
4. 可根据具体需求调整数据同步策略和卡片交互方式
Logo

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

更多推荐