HarmonyOS 7 外设上线回调重复怎么办?PartnerAgentExtensionAbility 去重与延迟销毁

同一块手表在页面里出现两次,不一定是扫描错了。PartnerAgentExtensionAbility 可能因 BLE 扫描或 ACL 连接收到设备发现信号;如果每个回调都追加列表,就会把状态更新误当成新设备。

伙伴设备发现、去重与三分钟清理时间线

先确认 API 26 的能力边界

官方指南说明 onDeviceDiscovered 可由扫描发现或连接成功触发;设备断开后 Extension 进程延迟约三分钟销毁;onDestroyWithReason 是最终清理资源的重要信号。

  • 发现事件应按设备身份 upsert,不应直接 append。
  • 在线状态与 Extension 进程是否仍存活是两个概念。
  • 资源清理必须幂等,允许多个退出路径重复调用。

案例一:扫描和连接各回调一次,列表出现两个相同设备

先规范化地址格式与 addressType,再生成会话键。若产品提供更稳定的设备标识,应优先使用产品标识。

interface Address { address?: string; addressType?: number }
function deviceKey(input: Address): string {
  const value = (input.address || '').trim().toUpperCase().replace(/-/g, ':')
  if (!/^([0-9A-F]{2}:){5}[0-9A-F]{2}$/.test(value)) throw new Error('地址无效')
  return String(input.addressType ?? -1) + '|' + value
}
console.assert(deviceKey({ address: 'aa-bb-cc-dd-ee-ff', addressType: 1 }) === '1|AA:BB:CC:DD:EE:FF')

格式差异不会再创建第二个会话,同时 seenCount 仍可记录回调次数用于排查。

案例二:蓝牙一断开就清空全部状态,短时间重连反复初始化

进程延迟销毁不代表设备仍在线。状态应区分 online、grace 和 destroyed;最终资源释放以系统销毁回调为准。

type Phase = 'online' | 'grace' | 'destroyed'
interface Life { phase: Phase; disconnectedAt?: number }
function shouldRelease(state: Life, now: number, grace = 180000): boolean {
  return state.phase === 'grace' && state.disconnectedAt !== undefined && now - state.disconnectedAt >= grace
}
const state: Life = { phase: 'grace', disconnectedAt: 1000 }
console.assert(!shouldRelease(state, 180999))
console.assert(shouldRelease(state, 181000))

宽限期内设备显示离线但可保留必要会话信息,系统真正销毁时再执行幂等清理。

现象与判断对照

现象优先检查处理原则
同一设备出现两次地址归一化与 upsert更新同一会话
断开后仍显示在线在线与进程存活是否混用拆分 phase
三分钟内重连很慢是否过早销毁全部缓存保留可复用状态
页面退出后仍有任务销毁回调是否清理幂等释放资源

为什么选择这个实现

事件去重不是丢弃第二次回调,而是把回调合并为同一会话的状态更新。这样既不重复显示,也保留了调试所需的发现次数和时间。

可复用边界

设备注册表可复用到手表、耳机等伙伴设备;设备身份策略必须允许产品层替换,不能把蓝牙地址永久写死成唯一账号标识。

验证记录

已验证地址大小写与分隔符归一化、重复发现只保留一个会话、179999ms 不释放、180000ms 到期以及重复 cleanup 不抛错。

本文的策略代码已在宿主 JavaScript 环境执行断言,用来验证状态、排序、去重或边界计算。它不等同于 HarmonyOS 7 API 26 工程编译,也不等同于真机系统能力验证;涉及系统回调、设备能力、窗口形态或跨应用 IPC 的部分,仍应在对应 SDK 与设备上完成端到端验收。

上线前检查清单

  • 设备身份键来源明确
  • 发现事件使用 upsert
  • 在线与进程存活分开
  • 宽限期内 UI 显示离线
  • onDestroyWithReason 幂等清理
  • 真实伙伴设备完成扫描和断连测试

官方资料

发现回调是会话更新信号,销毁回调才是资源释放边界。把这两件事分开,重复设备和重连抖动会一起减少。

Logo

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

更多推荐