HarmonyOS 穿戴协同实战:设备选择、授权与轻量消息 📅 2026/7/27 16:10:02 HarmonyOS 穿戴协同实战设备选择、授权与轻量消息穿戴协同不是把手机通知简单推到手表上。真实项目里更容易踩坑的是没有让用户明确选择设备任务消息发得太大手表离线时没有补偿授权关系也没有撤销入口。结果就是用户觉得“手表一直被打扰”开发者却很难判断消息到底发给了谁。本文围绕一个轻量场景展开手机端选择一块穿戴设备把运动任务、会议提醒这类小消息发送到手表端。重点放在工程边界设备选择、授权记录、消息压缩、失败补偿和验证方式。1. 先明确穿戴协同的边界边界手机端负责手表端负责设备选择展示可用设备让用户选择暴露可连接状态授权关系记录用户同意和撤销不主动越权接收消息内容压缩成轻量任务展示与反馈失败处理记录未送达等待重试下次连接后接收2. 官方资料与工程适用范围建议从华为开发者文档中心检索 Wear Engine、穿戴设备连接、多设备协同、权限和隐私说明相关资料华为开发者文档中心https://developer.huawei.com/consumer/cn/doc/HarmonyOS 指南入口https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/本文示例适用于这类业务业务适合发送到手表吗原因运动任务提醒适合内容短、实时性明确喝水/日程提醒适合轻量提醒交互简单长文章正文不适合信息量过大手表阅读体验差大图或复杂表单不适合传输和展示成本都高实际接入设备发现、通信通道和授权 API 时以当前 Wear Engine / HarmonyOS SDK 文档为准。本文代码强调架构和数据边界。3. 先定义可协同设备不要在业务代码里直接保存一堆字符串。先把设备信息抽象出来后面授权、消息发送、重试都依赖同一份设备 ID。// common/wearable/WearableDevice.etsexportinterfaceWearableDevice{deviceId:string;name:string;deviceType:watch|band;online:boolean;batteryLevel?:number;}exportfunctionisDeviceAvailable(device:WearableDevice):boolean{returndevice.onlinedevice.deviceId.length0;}代码解释点说明职责边界描述可协同设备不处理 UI 和通信输入约束deviceId必须稳定不能用设备名称代替避免的问题防止同名设备或离线设备被误发下一层连接设备选择器和授权记录都使用deviceId4. 设备选择要显式不要默认乱发如果用户有多块手表或手环应用不能默认把任务发到第一个设备。设备选择器应该展示在线状态并只允许选择可用设备。// entry/src/main/ets/components/WearableDevicePicker.etsimport{WearableDevice,isDeviceAvailable}from../../common/wearable/WearableDevice;Componentexportstruct WearableDevicePicker{devices:WearableDevice[][];selectedId:string;onSelect:(deviceId:string)void(){};build(){Column({space:12}){Text(选择穿戴设备).fontSize(22).fontWeight(FontWeight.Bold)ForEach(this.devices,(device:WearableDevice){Row(){Column({space:4}){Text(device.name).fontSize(17)Text(device.online?在线可用:当前离线).fontSize(12).fontColor(device.online?#047857:#98A2B3)}Blank()Text(device.deviceIdthis.selectedId?已选择:选择).fontSize(14).fontColor(isDeviceAvailable(device)?#2563EB:#98A2B3)}.padding(14).backgroundColor(device.deviceIdthis.selectedId?#E0F2FE:#FFFFFF).borderRadius(16).enabled(isDeviceAvailable(device)).onClick(()this.onSelect(device.deviceId))},(device:WearableDevice)device.deviceId)}}}这段组件的边界是设备选择。它不发消息只负责把用户选择的deviceId交出去。这样可以防止业务层绕过用户选择直接推送。5. 授权记录要可撤销用户同意把任务发送到手表不代表永远同意。授权状态应该能查询、更新、撤销。// common/wearable/WearableConsentStore.etsexportinterfaceWearableConsent{deviceId:string;enabled:boolean;grantedAt:number;}exportclassWearableConsentStore{privatestaticrecords:WearableConsent[][];staticgrant(deviceId:string):void{constnowDate.now();WearableConsentStore.recordsWearableConsentStore.records.filter(itemitem.deviceId!deviceId);WearableConsentStore.records.push({deviceId,enabled:true,grantedAt:now});}staticrevoke(deviceId:string):void{WearableConsentStore.recordsWearableConsentStore.records.map(item{if(item.deviceId!deviceId){returnitem;}return{...item,enabled:false};});}staticcanSend(deviceId:string):boolean{returnWearableConsentStore.records.some(itemitem.deviceIddeviceIditem.enabled);}}这段代码只管理授权状态不负责权限弹窗或通信发送。它防止“选择过一次设备后永远可发”的隐患也方便设置页提供关闭入口。6. 消息要轻量手表不是小手机穿戴设备适合短消息和明确动作不适合传完整业务对象。建议把消息压缩成任务类型、标题、摘要、时间戳和业务 ID。// common/wearable/WearableMessageCodec.etsexportinterfaceWearableTaskMessage{taskId:string;type:sport|meeting|water;title:string;summary:string;createdAt:number;}exportclassWearableMessageCodec{staticencode(message:WearableTaskMessage):string{returnJSON.stringify({id:message.taskId,t:message.type,title:message.title.slice(0,24),text:message.summary.slice(0,48),at:message.createdAt});}staticisValidPayload(payload:string):boolean{returnpayload.length0payload.length1024;}}代码解释点说明职责边界把业务消息转换成穿戴端轻量负载输入约束标题和摘要必须截断避免过大避免的问题防止把大对象、长文本、图片塞进消息下一层连接发送器只处理已经压缩过的 payload7. 发送前同时检查设备和授权发送器不要只看设备在线也要看用户是否授权。两个条件缺一不可。// common/wearable/WearableTaskSender.etsimport{WearableDevice,isDeviceAvailable}from./WearableDevice;import{WearableConsentStore}from./WearableConsentStore;import{WearableMessageCodec,WearableTaskMessage}from./WearableMessageCodec;exporttypeSendResultsent|device_unavailable|consent_missing|payload_invalid;exportclassWearableTaskSender{staticsend(device:WearableDevice,message:WearableTaskMessage):SendResult{if(!isDeviceAvailable(device)){returndevice_unavailable;}if(!WearableConsentStore.canSend(device.deviceId)){returnconsent_missing;}constpayloadWearableMessageCodec.encode(message);if(!WearableMessageCodec.isValidPayload(payload)){returnpayload_invalid;}// 实际项目中这里接入 Wear Engine 或多设备通信能力。returnsent;}}这段代码的价值是把失败原因明确化。调用方可以根据device_unavailable、consent_missing、payload_invalid给出不同提示而不是统一显示“发送失败”。8. 离线失败要进入补偿队列手表不一定一直在线。任务消息如果不是强实时可以在设备恢复连接后补发。// common/wearable/WearableRetryQueue.etsimport{WearableTaskMessage}from./WearableMessageCodec;exportinterfacePendingWearableTask{deviceId:string;message:WearableTaskMessage;retryCount:number;createdAt:number;}exportclassWearableRetryQueue{privatestatictasks:PendingWearableTask[][];staticenqueue(deviceId:string,message:WearableTaskMessage):void{WearableRetryQueue.tasks.push({deviceId,message,retryCount:0,createdAt:Date.now()});}statictake(deviceId:string):PendingWearableTask[]{constmatchedWearableRetryQueue.tasks.filter(itemitem.deviceIddeviceId);WearableRetryQueue.tasksWearableRetryQueue.tasks.filter(itemitem.deviceId!deviceId);returnmatched;}}补偿队列的边界是“未送达任务”。它不负责展示也不负责真正通信。这样设备恢复在线时可以从一个入口取出待发送消息。9. 页面提示要按失败原因区分用户需要知道为什么没发出去是设备离线、未授权还是内容不符合要求。exportfunctionwearableSendTip(result:SendResult):string{switch(result){casesent:return已发送到手表;casedevice_unavailable:return手表当前不可用任务已等待下次连接;caseconsent_missing:return请先授权该设备接收任务;casepayload_invalid:return任务内容过长请精简后再发送;default:return发送状态未知;}}这段提示函数不直接弹窗只把工程状态转成用户能理解的话。它能减少客服和测试反馈里的“失败但不知道为什么”。10. 验证流程验证动作预期结果多设备同时在线用户可以明确选择目标设备未授权直接发送阻止发送并提示先授权手表离线发送进入补偿队列不丢任务消息内容过长被拦截或截断不发送大对象撤销授权后再发送不再允许发送到该设备穿戴协同一定要用真设备验证。模拟数据可以验证页面和状态但无法覆盖设备连接、离线恢复、消息到达时机等问题。建议给协同链路增加一份调试记录至少记录目标设备、发送结果和 payload 大小。这样出现“手表没收到”时可以先判断消息有没有发出、是不是发给了正确设备、是否因为离线进入补偿队列。import{SendResult}from./WearableTaskSender;exportinterfaceWearableSendLog{deviceId:string;result:SendResult;payloadSize:number;at:number;}exportfunctioncreateWearableSendLog(deviceId:string,result:SendResult,payload:string):WearableSendLog{return{deviceId,result,payloadSize:payload.length,at:Date.now()};}这段日志对象不保存敏感内容只保存排查必要字段。它防止为了排查问题把完整消息正文写进日志兼顾定位和隐私边界。11. 常见问题排查现象可能原因检查方法修复建议消息发错设备没有显式选择设备查看发送时 deviceId增加设备选择和确认用户关闭后仍收到授权状态没有撤销检查 consent 记录增加撤销入口手表端显示不完整消息过长或字段太多打印 payload 长度压缩字段和摘要离线后任务丢失没有补偿队列断开手表复测未送达任务入队测试通过真机失败只用了模拟数据真设备连接验证引入设备状态回调12. 发布前检查表检查项判定用户能看到目标设备不默认乱发授权可开启也可关闭设置页有撤销入口消息 payload 有大小控制不传长文本和大对象离线任务有记录失败可补偿真机手表验证通过不只测模拟数据发布前建议把检查表拆给两个角色客户端开发确认设备选择、授权、消息体和重试逻辑测试同学确认真机连接、离线恢复、撤销授权和多设备选择。穿戴协同的问题经常跨手机端和手表端如果只让一个人简单勾选很容易遗漏设备状态变化。角色必查内容客户端开发deviceId是否稳定、授权是否可撤销、payload 是否受控手表端开发接收字段是否兼容、展示是否能处理缺省值测试多设备、离线、撤销授权、重复发送产品提醒频率和文案是否打扰用户13. 工程小结穿戴协同的关键是克制。手机负责选择、授权、压缩和补偿手表只承接轻量任务和即时反馈。只要设备 ID 稳定、授权关系清楚、消息体足够小、失败状态可追踪协同体验就不会变成“通知乱飞”。后续扩展到健康提醒、运动任务、日程提醒时也可以沿用同一套边界。