
HarmonyOS NEXT 开发里,startDiscovery 这个 API 经常被误用。很多人第一次接触 NearLink Kit 的设备发现能力时,会发现官方示例能运行,但放到实际项目里就遇到各种问题:扫描结果重复、回调不触发、页面离开后扫描还在跑。这个功能本身不复杂,但真正麻烦的是生命周期管理和扫描结果的去重处理。
NearLink Kit 是 HarmonyOS 提供的星闪通信服务框架。设备发现是星闪应用的第一步——扫描周边的星闪设备并获取设备的基础信息,比如设备名称、设备ID、信号强度等。
| 特性 | 传统蓝牙扫描 | 星闪设备发现 |
|---|---|---|
| 扫描模式 | 被动扫描 | 主动+被动混合 |
| 发现速度 | 慢(约3-5秒) | 快(约1-2秒) |
| 设备信息量 | 有限 | 更丰富 |
| 过滤能力 | 有限 | 支持多维度过滤 |
有两个典型场景适合用这个 API:
不适合的场景:如果你只需要连接已知设备,直接使用连接 API 即可,没必要开启扫描。
在 module.json5 中添加权限声明。这一步容易漏掉,很多人直接跑示例发现没反应,原因就是权限没配。
注意:NEARLINK_DISCOVERY 权限在 API 23 及以上版本才支持。如果跑在低版本设备上,这个权限不会生效,也不会报错,扫描就直接不回调了。
这一段代码用于封装星闪发现的核心逻辑。实际项目里建议写成一个单独的服务类,不要直接把扫描逻辑塞进 UI 组件。
关键细节:
onFound 回调会反复上报同一个设备,信号强度变化时也会再次回调。使用 deviceId 作为 Map 的 key 去重,只更新已存在设备的 RSSI,不重复添加。startDiscovery 返回一个 id,停止时要传入这个 id。如果页面销毁时没有保存这个 id,后续无法正确停止扫描。DISCOVERY_FILTER_TYPE_MANUFACTURER 过滤效率更高。这段代码展示如何在 UI 组件中调用发现服务,并处理生命周期。
注意 aboutToDisappear 中的 stopScan() 调用。实际项目里很多人漏掉这一步,导致页面返回后扫描还在持续,不仅耗电,还可能造成回调在已销毁页面中执行,引发异常。
如果不希望扫描所有设备,可以用制造商数据过滤。这段代码展示如何只发现特定厂商的设备。
现象:从扫描页面返回,过一会儿发现手机还在发热,日志显示扫描回调仍在触发。
原因:aboutToDisappear 中没有调用 stopDiscovery。HarmonyOS 不会在页面销毁时自动停止已启动的扫描,需要开发者手动处理。
解决方案:严格在 aboutToDisappear 中停止扫描。如果服务类被多个页面共享,需要在服务类里判断是否有页面还在使用扫描,不要直接 stop。
现象:一个设备在 3 秒内被回调 10 次,页面列表疯狂刷新。
原因:星闪设备会主动广播,每次收到广播都会触发回调。这不是 bug,而是星闪协议本身的特性。
解决方案:使用 deviceId 做去重,如上面的代码所示。注意:只更新 RSSI 等动态数据,不重复添加列表项。
不要把扫描逻辑直接写在 UI 组件里。扫描涉及状态管理、生命周期、回调处理,拆成独立服务类后测试和复用都更方便。
stopDiscovery 必须在页面销毁时调用。这不是可选的。如果忘记停止,扫描会持续消耗电量,而且回调中操作 UI 时可能因为页面已销毁而崩溃。
回调中更新 UI 时注意线程。onFound 运行在非 UI 线程,不要直接操作 UI 组件。ArkTS 的 @State 变量是线程安全的,赋值即可触发刷新。但如果有复杂的 UI 操作,建议使用 setTimeout 或 postTask 切回主线程。
Q:为什么真机正常,模拟器不生效?
A:星闪能力依赖硬件支持,模拟器不具备星闪硬件,所以 startDiscovery 调用后不会触发任何回调。必须在 real device 上测试。
Q:为什么页面返回后状态丢失?
A:检查 aboutToDisappear 是否正确调用了 stopDiscovery。另外,如果你在页面间切换时使用了 NavStack,注意 onPageShow 和 onPageHide 的生命周期,建议在 onPageHide 中暂停扫描,onPageShow 中恢复。
Q:过滤条件设置后,扫描不到设备怎么办?
A:先去掉 filter,测试是否能看到设备。如果能看见,说明 filter 配置错误。确认你的 filter value 和设备广播的制造商数据完全匹配(包括字节序和长度)。
如果你也遇到类似问题,可以重点检查生命周期和状态同步逻辑。不同设备上的星闪广播行为可能存在差异,建议真机测试。
原文作者:不羁的木木;如有侵权,请联系管理员删除。