鸿蒙跨端姿势提醒系统开发指南 原创

进修的泡芙
发布于 2025-6-22 17:04
浏览
0收藏

鸿蒙跨端姿势提醒系统开发指南

一、项目概述

本文基于HarmonyOS的姿态识别能力和分布式技术,开发一款智能姿势提醒系统。该系统能够通过设备摄像头或传感器检测用户坐姿,在发现不良姿势时向多设备发送提醒,借鉴了《鸿蒙跨端U同步》中多设备数据同步的技术原理。

二、系统架构

±--------------------+ ±--------------------+ ±--------------------+
主设备 <-----> 分布式数据总线 <-----> 从设备
(手机/平板) (Distributed Bus) (智能手表/其他设备)
±---------±---------+ ±---------±---------+ ±---------±---------+

±---------v----------+ ±---------v----------+ ±---------v----------+
姿态检测模块 提醒管理模块 数据同步模块
(Posture Detect) (Alert Manager) (Data Sync)

±--------------------+ ±--------------------+ ±--------------------+

三、核心代码实现
姿势检测服务

// src/main/ets/service/PostureService.ts
import { distributedData } from ‘@ohos.data.distributedData’;
import { BusinessError } from ‘@ohos.base’;
import { camera } from ‘@ohos.multimedia.camera’;
import { image } from ‘@ohos.multimedia.image’;
import { poseDetection } from ‘@ohos.ai.poseDetection’;
import { sensor } from ‘@ohos.sensor’;

interface PostureData {
postureType: ‘good’ ‘bad’
‘unknown’;
confidence: number;
timestamp: number;
joints?: {
[key: string]: {
x: number;
y: number;
score: number;
};

interface PostureAlert {

type: ‘slouching’ ‘leaning’ ‘head_down’
‘cross_legs’;
timestamp: number;
duration: number;
severity: ‘low’ ‘medium’
‘high’;
export class PostureService {

private static instance: PostureService;
private kvStore: distributedData.KVStore | null = null;
private readonly STORE_ID = ‘posture_data_store’;
private cameraInput: camera.CameraInput | null = null;
private previewOutput: camera.PreviewOutput | null = null;
private poseDetector: poseDetection.PoseDetector | null = null;
private motionSensor: sensor.Sensor | null = null;
private currentPosture: PostureData = {
postureType: ‘unknown’,
confidence: 0,
timestamp: Date.now()
};
private postureAlerts: PostureAlert[] = [];

private constructor() {
this.initKVStore();
this.initCamera();
this.initPoseDetector();
this.initMotionSensor();
public static getInstance(): PostureService {

if (!PostureService.instance) {
  PostureService.instance = new PostureService();

return PostureService.instance;

private async initKVStore(): Promise<void> {

try {
  const options: distributedData.KVManagerConfig = {
    bundleName: 'com.example.posture',
    userInfo: {
      userId: '0',
      userType: distributedData.UserType.SAME_USER_ID

};

  const kvManager = distributedData.createKVManager(options);
  this.kvStore = await kvManager.getKVStore({
    storeId: this.STORE_ID,
    options: {
      createIfMissing: true,
      encrypt: false,
      backup: false,
      autoSync: true,
      kvStoreType: distributedData.KVStoreType.SINGLE_VERSION

});

  this.kvStore.on('dataChange', distributedData.SubscribeType.SUBSCRIBE_TYPE_REMOTE, (data) => {
    data.insertEntries.forEach((entry: distributedData.Entry) => {
      if (entry.key === 'posture_data') {
        this.notifyPostureChange(entry.value.value as PostureData);

else if (entry.key === ‘posture_alerts’) {

        this.notifyAlertsChange(entry.value.value as PostureAlert[]);

});

  });

catch (e) {

  console.error(Failed to initialize KVStore. Code: {e.code}, message: {e.message});

}

private async initCamera(): Promise<void> {
try {
const cameraManager = camera.getCameraManager();
const cameras = cameraManager.getSupportedCameras();
if (cameras.length === 0) {
console.error(‘No camera available’);
return;
// 使用前置摄像头

  this.cameraInput = cameraManager.createCameraInput(cameras[0]);
  await this.cameraInput.open();
  
  // 创建预览输出
  const surfaceId = 'previewSurface';
  this.previewOutput = cameraManager.createPreviewOutput(surfaceId);
  
  // 创建会话并开始预览
  const captureSession = cameraManager.createCaptureSession();
  await captureSession.beginConfig();
  await captureSession.addInput(this.cameraInput);
  await captureSession.addOutput(this.previewOutput);
  await captureSession.commitConfig();
  await captureSession.start();

catch (e) {

  console.error(Failed to initialize camera. Code: {e.code}, message: {e.message});

}

private async initPoseDetector(): Promise<void> {
try {
const config: poseDetection.PoseDetectorConfig = {
modelType: poseDetection.ModelType.LITE,
scoreThreshold: 0.5,
nmsRadius: 20
};

  this.poseDetector = await poseDetection.createPoseDetector(config);

catch (e) {

  console.error(Failed to initialize pose detector. Code: {e.code}, message: {e.message});

}

private async initMotionSensor(): Promise<void> {
try {
this.motionSensor = await sensor.getDefaultSensor(sensor.SensorType.SENSOR_TYPE_ACCELEROMETER);

  this.motionSensor.on('change', (data: sensor.AccelerometerResponse) => {
    this.detectPostureFromMotion(data);
  });
  
  await this.motionSensor.setInterval(1000); // 1秒采样一次

catch (e) {

  console.error(Failed to initialize motion sensor. Code: {e.code}, message: {e.message});

}

private async detectPostureFromImage(imageObj: image.Image): Promise<void> {
if (!this.poseDetector) return;

try {
  const result = await this.poseDetector.detect(imageObj);
  this.analyzePose(result);
  imageObj.release();

catch (e) {

  console.error(Failed to detect pose. Code: {e.code}, message: {e.message});

}

private detectPostureFromMotion(data: sensor.AccelerometerResponse): void {
// 简化的姿势检测逻辑 (基于加速度计数据)
const x = data.x;
const y = data.y;
const z = data.z;

// 计算设备倾斜角度
const angleX = Math.atan2(y, z) * (180 / Math.PI);
const angleY = Math.atan2(x, z) * (180 / Math.PI);

let postureType: 'good' 'bad'

‘unknown’ = ‘unknown’;
let confidence = 0;

// 简单的角度判断
if (Math.abs(angleX) > 30 || Math.abs(angleY) > 30) {
  postureType = 'bad';
  confidence = 0.7;

else {

  postureType = 'good';
  confidence = 0.8;

this.currentPosture = {

  postureType,
  confidence,
  timestamp: Date.now()
};

this.checkForBadPosture();
this.scheduleSync();

private analyzePose(pose: poseDetection.Pose): void {

if (!pose.keypoints || pose.keypoints.length === 0) return;

// 获取关键点
const nose = pose.keypoints.find(k => k.name === 'nose');
const leftShoulder = pose.keypoints.find(k => k.name === 'left_shoulder');
const rightShoulder = pose.keypoints.find(k => k.name === 'right_shoulder');

if (!nose |!leftShoulder

| !rightShoulder) return;

// 计算肩膀中点
const shoulderMidX = (leftShoulder.x + rightShoulder.x) / 2;
const shoulderMidY = (leftShoulder.y + rightShoulder.y) / 2;

// 计算鼻子与肩膀中点的垂直距离
const verticalDistance = nose.y - shoulderMidY;
const horizontalDistance = Math.abs(nose.x - shoulderMidX);

let postureType: 'good' 'bad'

‘unknown’ = ‘unknown’;
let confidence = 0;

// 简化的姿势判断逻辑
if (verticalDistance < 0 || horizontalDistance > verticalDistance * 0.5) {
  postureType = 'bad';
  confidence = pose.score * 0.8;

else {

  postureType = 'good';
  confidence = pose.score * 0.9;

this.currentPosture = {

  postureType,
  confidence,
  timestamp: Date.now(),
  joints: pose.keypoints.reduce((acc, k) => {
    acc[k.name] = { x: k.x, y: k.y, score: k.score };
    return acc;
  }, {})
};

this.checkForBadPosture();
this.scheduleSync();

private checkForBadPosture(): void {

if (this.currentPosture.postureType !== 'bad') return;

const now = Date.now();
const lastAlert = this.postureAlerts[this.postureAlerts.length - 1];

// 判断不良姿势类型
let alertType: PostureAlert['type'] = 'slouching';
let severity: PostureAlert['severity'] = 'low';

// 简化的严重程度判断
if (this.currentPosture.confidence > 0.7) {
  severity = 'high';

else if (this.currentPosture.confidence > 0.5) {

  severity = 'medium';

// 合并连续的相同类型提醒

if (lastAlert && lastAlert.type === alertType && now - lastAlert.timestamp < 10000) {
  lastAlert.duration = now - lastAlert.timestamp;
  lastAlert.severity = severity;

else {

  this.postureAlerts.push({
    type: alertType,
    timestamp: now,
    duration: 0,
    severity
  });

// 触发提醒

this.triggerAlert(alertType, severity);

private triggerAlert(type: PostureAlert[‘type’], severity: PostureAlert[‘severity’]): void {

// 实际应用中应该使用通知服务
console.log(Posture alert: {type} ({severity}));

// 同步提醒状态
if (this.kvStore) {
  this.kvStore.put('posture_alert', {
    value: {
      type,
      severity,
      timestamp: Date.now()

});

}

private scheduleSync(): void {
if (this.syncTimer) {
clearTimeout(this.syncTimer);
this.syncTimer = setTimeout(() => {

  this.syncData();
  this.syncTimer = null;
}, 2000); // 2秒内多次更新只同步一次

private syncTimer: number | null = null;

private async syncData(): Promise<void> {
if (!this.kvStore) return;

try {
  await this.kvStore.put('posture_data', { value: this.currentPosture });
  await this.kvStore.put('posture_alerts', { value: this.postureAlerts });

catch (e) {

  console.error(Failed to sync data. Code: {e.code}, message: {e.message});

}

private notifyPostureChange(newPosture: PostureData): void {
// 使用时间戳解决冲突 - 保留最新的姿势数据
if (newPosture.timestamp > this.currentPosture.timestamp) {
this.currentPosture = newPosture;
}

private notifyAlertsChange(newAlerts: PostureAlert[]): void {
// 合并新旧提醒
const mergedAlerts = […this.postureAlerts];

newAlerts.forEach(newAlert => {
  const existingIndex = mergedAlerts.findIndex(a => 
    a.type === newAlert.type && 
    Math.abs(a.timestamp - newAlert.timestamp) < 5000
  );
  
  if (existingIndex >= 0) {
    if (newAlert.timestamp > mergedAlerts[existingIndex].timestamp) {
      mergedAlerts[existingIndex] = newAlert;

} else {

    mergedAlerts.push(newAlert);

});

this.postureAlerts = mergedAlerts;

public async getCurrentPosture(): Promise<PostureData> {

if (!this.kvStore) return this.currentPosture;

try {
  const entry = await this.kvStore.get('posture_data');
  return entry?.value || this.currentPosture;

catch (e) {

  console.error(Failed to get posture data. Code: {e.code}, message: {e.message});
  return this.currentPosture;

}

public async getRecentAlerts(): Promise<PostureAlert[]> {
if (!this.kvStore) return this.postureAlerts;

try {
  const entry = await this.kvStore.get('posture_alerts');
  return entry?.value || this.postureAlerts;

catch (e) {

  console.error(Failed to get posture alerts. Code: {e.code}, message: {e.message});
  return this.postureAlerts;

}

public async destroy(): Promise<void> {
if (this.kvStore) {
this.kvStore.off(‘dataChange’);
if (this.cameraInput) {

  await this.cameraInput.close();

if (this.poseDetector) {

  this.poseDetector.release();

if (this.motionSensor) {

  this.motionSensor.off('change');

}

姿势监测组件

// src/main/ets/components/PostureMonitor.ets
@Component
export struct PostureMonitor {
private postureService = PostureService.getInstance();
@State currentPosture: PostureData = {
postureType: ‘unknown’,
confidence: 0,
timestamp: 0
};
@State alerts: PostureAlert[] = [];
@State previewSurfaceId: string = ‘previewSurface’;

aboutToAppear(): void {
this.loadPostureData();
private async loadPostureData(): Promise<void> {

this.currentPosture = await this.postureService.getCurrentPosture();
this.alerts = await this.postureService.getRecentAlerts();

build() {

Stack() {
  // 摄像头预览
  CameraPreview({ surfaceId: this.previewSurfaceId })
    .width('100%')
    .height('100%');
  
  // 姿势状态覆盖层
  Column() {
    // 姿势状态指示器
    Row() {
      Circle()
        .width(20)
        .height(20)
        .fillColor(this.getPostureColor(this.currentPosture.postureType))
        .margin({ right: 10 });
      
      Text(this.getPostureText(this.currentPosture.postureType))
        .fontSize(18)
        .fontColor('#FFFFFF');

.padding(10)

    .backgroundColor('#88000000')
    .borderRadius(20)
    .margin({ bottom: 20 });
    
    // 姿势关键点可视化
    if (this.currentPosture.joints) {
      this.buildPoseSkeleton();

// 提醒通知

    if (this.alerts.length > 0) {
      this.buildAlertsDisplay();

}

  .width('100%')
  .height('100%')
  .padding(20)

.width(‘100%’)

.height('100%')
.onAppear(() => {
  this.postureService.getCurrentPosture().then((posture) => {
    this.currentPosture = posture;
  });
  this.postureService.getRecentAlerts().then((alerts) => {
    this.alerts = alerts;
  });
});

@Builder

private buildPoseSkeleton() {
Canvas({ context: new CanvasRenderingContext2D() })
.width(‘100%’)
.height(‘100%’)
.onReady((ctx: CanvasRenderingContext2D) => {
ctx.strokeStyle = ‘#FF4081’;
ctx.lineWidth = 3;

    // 绘制关键点之间的连线
    const joints = this.currentPosture.joints;
    if (!joints) return;
    
    // 头部连线
    if (joints['nose'] && joints['left_eye'] && joints['right_eye']) {
      ctx.beginPath();
      ctx.moveTo(joints['left_eye'].x, joints['left_eye'].y);
      ctx.lineTo(joints['nose'].x, joints['nose'].y);
      ctx.lineTo(joints['right_eye'].x, joints['right_eye'].y);
      ctx.stroke();

// 肩膀连线

    if (joints['left_shoulder'] && joints['right_shoulder']) {
      ctx.beginPath();
      ctx.moveTo(joints['left_shoulder'].x, joints['left_shoulder'].y);
      ctx.lineTo(joints['right_shoulder'].x, joints['right_shoulder'].y);
      ctx.stroke();

// 左臂连线

    if (joints['left_shoulder'] && joints['left_elbow'] && joints['left_wrist']) {
      ctx.beginPath();
      ctx.moveTo(joints['left_shoulder'].x, joints['left_shoulder'].y);
      ctx.lineTo(joints['left_elbow'].x, joints['left_elbow'].y);
      ctx.lineTo(joints['left_wrist'].x, joints['left_wrist'].y);
      ctx.stroke();

// 右臂连线

    if (joints['right_shoulder'] && joints['right_elbow'] && joints['right_wrist']) {
      ctx.beginPath();
      ctx.moveTo(joints['right_shoulder'].x, joints['right_shoulder'].y);
      ctx.lineTo(joints['right_elbow'].x, joints['right_elbow'].y);
      ctx.lineTo(joints['right_wrist'].x, joints['right_wrist'].y);
      ctx.stroke();

// 绘制关键点

    Object.values(joints).forEach(joint => {
      if (joint.score > 0.3) {
        ctx.fillStyle = '#4CAF50';
        ctx.beginPath();
        ctx.arc(joint.x, joint.y, 5, 0, 2 * Math.PI);
        ctx.fill();

});

  });

@Builder

private buildAlertsDisplay() {
Column() {
Text(‘姿势提醒’)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor(‘#FFFFFF’)
.margin({ bottom: 10 });

  ForEach(this.alerts.slice(0, 3), (alert) => {
    Row() {
      Image($r('app.media.ic_warning'))
        .width(20)
        .height(20)
        .margin({ right: 10 });
      
      Text(this.getAlertText(alert.type))
        .fontSize(16)
        .fontColor('#FFFFFF')
        .layoutWeight(1);
      
      Text(${Math.floor(alert.duration / 1000)}秒)
        .fontSize(14)
        .fontColor('#FFC107');

.padding(10)

    .backgroundColor('#88000000')
    .borderRadius(10)
    .margin({ bottom: 10 });
  })

.width(‘80%’)

.padding(15)
.backgroundColor('#88000000')
.borderRadius(15)
.position({ x: '10%', y: '70%' });

private getPostureColor(type: ‘good’ ‘bad’
‘unknown’): string {

switch (type) {
  case 'good': return '#4CAF50';
  case 'bad': return '#F44336';
  default: return '#FFC107';

}

private getPostureText(type: ‘good’ ‘bad’
‘unknown’): string {
switch (type) {
case ‘good’: return ‘姿势良好’;
case ‘bad’: return ‘不良姿势’;
default: return ‘检测中…’;
}

private getAlertText(type: PostureAlert[‘type’]): string {
switch (type) {
case ‘slouching’: return ‘驼背警告’;
case ‘leaning’: return ‘身体倾斜’;
case ‘head_down’: return ‘低头警告’;
case ‘cross_legs’: return ‘翘二郎腿’;
default: return ‘姿势问题’;
}

主界面实现

// src/main/ets/pages/PosturePage.ets
import { PostureService } from ‘…/service/PostureService’;
import { PostureMonitor } from ‘…/components/PostureMonitor’;

@Entry
@Component
struct PosturePage {
@State activeTab: number = 0;
@State deviceList: string[] = [];
private postureService = PostureService.getInstance();

build() {
Column() {
// 标题
Text(‘智能姿势提醒’)
.fontSize(24)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 20 });

  // 标签页
  Tabs({ barPosition: BarPosition.Start }) {
    TabContent() {
      // 实时监测标签页
      PostureMonitor()

.tabBar(‘实时监测’);

    TabContent() {
      // 历史记录标签页
      this.buildHistoryTab()

.tabBar(‘历史记录’);

    TabContent() {
      // 设备管理标签页
      this.buildDevicesTab()

.tabBar(‘设备管理’);

.barWidth(‘100%’)

  .barHeight(50)
  .width('100%')
  .height('80%')

.width(‘100%’)

.height('100%')
.padding(20)
.onAppear(() => {
  // 模拟获取设备列表
  setTimeout(() => {
    this.deviceList = ['我的手机', '智能手表', '平板电脑'];
  }, 1000);
});

@Builder

private buildHistoryTab() {
Column() {
Text(‘姿势历史记录’)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 20 });

  // 模拟历史数据
  List({ space: 15 }) {
    ListItem() {
      this.buildHistoryItem('驼背警告', '高', '10分钟前', '持续2分钟');

ListItem() {

      this.buildHistoryItem('低头警告', '中', '30分钟前', '持续1分钟');

ListItem() {

      this.buildHistoryItem('身体倾斜', '低', '1小时前', '持续30秒');

}

  .width('100%')
  .layoutWeight(1);

.width(‘100%’)

.height('100%')
.padding(10);

@Builder

private buildHistoryItem(
type: string,
severity: string,
time: string,
duration: string
) {
Row() {
Column() {
Text(type)
.fontSize(16)
.fontWeight(FontWeight.Bold);

    Text(严重程度: ${severity})
      .fontSize(14)
      .fontColor('#666666')
      .margin({ top: 5 });

.layoutWeight(1);

  Column() {
    Text(time)
      .fontSize(14)
      .fontColor('#666666');
    
    Text(duration)
      .fontSize(12)
      .fontColor('#999999')
      .margin({ top: 5 });

}

.width('100%')
.padding(15)
.backgroundColor('#FFFFFF')
.borderRadius(10);

@Builder

private buildDevicesTab() {
Column() {
Text(‘已连接设备’)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 20 });

  if (this.deviceList.length > 0) {
    List({ space: 15 }) {
      ForEach(this.deviceList, (device) => {
        ListItem() {
          Row() {
            Image($r('app.media.ic_device'))
              .width(40)
              .height(40)
              .margin({ right: 15 });
            
            Text(device)
              .fontSize(16)
              .layoutWeight(1);
            
            if (device === '我的手机') {
              Text('主设备')
                .fontSize(14)
                .fontColor('#4CAF50');

}

          .width('100%')
          .padding(15)
          .backgroundColor('#FFFFFF')
          .borderRadius(10)

})

.width(‘100%’)

    .layoutWeight(1);

else {

    Text('没有连接的设备')
      .fontSize(16)
      .fontColor('#666666')
      .margin({ top: 50 });

Button(‘添加设备’)

    .type(ButtonType.Capsule)
    .width('80%')
    .margin({ top: 30 })
    .backgroundColor('#2196F3')
    .fontColor('#FFFFFF');

.width(‘100%’)

.height('100%')
.padding(10);

}

四、与游戏同步技术的结合点
分布式状态同步:借鉴游戏中多玩家状态同步机制,实现姿势数据的跨设备实时同步

实时数据处理:类似游戏中的实时数据流,处理传感器和摄像头数据

设备角色分配:类似游戏中的主机/客户端角色,确定主监测设备和从属设备

时间同步机制:确保多设备间的时间戳一致,类似游戏中的时间同步

数据压缩传输:优化姿势数据的传输效率,类似游戏中的网络优化

五、关键特性实现
姿势检测:

  private analyzePose(pose: poseDetection.Pose): void {
 const nose = pose.keypoints.find(k => k.name === 'nose');
 const shoulders = [
   pose.keypoints.find(k => k.name === 'left_shoulder'),
   pose.keypoints.find(k => k.name === 'right_shoulder')
 ];
 
 if (nose && shoulders.every(s => s)) {
   const shoulderMidY = (shoulders[0].y + shoulders[1].y) / 2;
   this.currentPosture = {
     postureType: nose.y > shoulderMidY ? 'bad' : 'good',
     confidence: pose.score,
     timestamp: Date.now()
   };

}

提醒触发:

  private checkForBadPosture(): void {
 if (this.currentPosture.postureType === 'bad') {
   const now = Date.now();
   const lastAlert = this.alerts[this.alerts.length - 1];
   
   if (lastAlert && now - lastAlert.timestamp < 10000) {
     lastAlert.duration = now - lastAlert.timestamp;

else {

     this.alerts.push({
       type: this.detectAlertType(),
       timestamp: now,
       duration: 0
     });

this.triggerAlert();

}

数据同步:

  private async syncData(): Promise<void> {
 if (this.kvStore) {
   await this.kvStore.put('posture_data', { value: this.currentPosture });
   await this.kvStore.put('posture_alerts', { value: this.alerts });

}

冲突解决:

  private notifyPostureChange(newPosture: PostureData): void {
 if (newPosture.timestamp > this.currentPosture.timestamp) {
   this.currentPosture = newPosture;

}

六、性能优化策略
传感器采样间隔:

  await this.motionSensor.setInterval(1000); // 1秒采样一次

图像分析节流:

  private lastAnalysisTime = 0;

private readonly ANALYSIS_INTERVAL = 2000; // 2秒分析一次

private async analyzeImage(imageObj: image.Image): Promise<void> {
const now = Date.now();
if (now - this.lastAnalysisTime < this.ANALYSIS_INTERVAL) {
imageObj.release();
return;
this.lastAnalysisTime = now;

 // 分析逻辑...

批量数据同步:

  private scheduleSync(): void {
 if (this.syncTimer) clearTimeout(this.syncTimer);
 this.syncTimer = setTimeout(() => {
   this.syncData();
   this.syncTimer = null;
 }, 2000); // 2秒内多次更新只同步一次

本地缓存优先:

  public async getCurrentPosture(): Promise<PostureData> {
 // 先返回本地缓存
 const cachedPosture = this.currentPosture;
 
 // 异步从分布式存储获取最新状态
 if (this.kvStore) {
   this.kvStore.get('posture_data').then((entry) => {
     if (entry?.value && entry.value.timestamp > cachedPosture.timestamp) {
       this.currentPosture = entry.value;

});

return cachedPosture;

七、项目扩展方向
个性化提醒设置:允许用户自定义提醒频率和方式

姿势矫正指导:提供改善姿势的具体方法和指导

长期趋势分析:统计姿势改善情况

工作休息提醒:结合久坐提醒功能

多场景适配:根据不同场景(办公、学习等)调整检测标准

八、总结

本姿势提醒系统实现了以下核心功能:
基于HarmonyOS传感器和摄像头能力的姿势检测

不良姿势实时识别与提醒

多设备间的状态同步

历史记录查看与分析

通过借鉴游戏中的多设备同步技术,我们构建了一个实用的健康监测工具。该项目展示了HarmonyOS在传感器数据处理和分布式技术方面的强大能力,为开发者提供了健康类应用开发的参考方案。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
收藏
回复
举报
回复
    相关推荐