4、广播与扫描避坑:广播类型选择、扫描窗口与间隔、定向广播与被动扫描

广播和扫描,是 BLE 连接建立前的“敲门砖”。

很多人觉得这步简单,不就是发个包、收个包吗?

我刚开始也这么想,直到在量产阶段发现设备死活连不上——查了三天,最后发现是广播类型选错了。嗯,从那以后我再也不敢小看这章了。

4.1 广播类型:选错了,设备就“隐身”了

BLE 广播分四种类型。我习惯把它们分成两类:可连接的和不可连接的。

广播类型 可连接 可扫描 典型场景
可连接非定向广播 ✅ ✅ 手机连接手环、传感器
可连接定向广播 ✅ ❌ 快速重连已知设备
不可连接非定向广播 ❌ ✅ 信标(Beacon)、温度广播
可扫描非定向广播 ❌ ✅ 需要扫描响应数据的广播

我在项目中遇到过最典型的坑:把信标设备配成了“可连接非定向广播”。结果手机扫描时,系统以为这是个可连接设备,自动弹配对框,用户体验极差。

避坑指南: 纯广播设备(如 Beacon)必须用“不可连接非定向广播”。否则手机端的连接管理器会误判,导致扫描列表异常。

4.2 定向广播:快,但有代价

定向广播,说白了就是“点名广播”。

它只发给一个指定的设备,其他设备收到这个包会直接丢弃。

好处是:连接建立快。我记得有一次做耳机回连优化,用定向广播把回连时间从 2 秒降到了 300 毫秒。

坏处是:功耗高。定向广播的间隔通常很短(3.75ms 起步),而且不能进入休眠。

我的经验: 定向广播只适合“已知设备快速重连”场景。如果你做的是开放配对(任何人都能连),千万别用定向广播——否则只有最后一个配对过的设备能连上。

4.3 扫描窗口与扫描间隔:调不好,要么漏包,要么费电

扫描参数有两个关键值:

  • 扫描窗口(Scan Window):每次扫描持续多长时间
  • 扫描间隔(Scan Interval):两次扫描开始之间的时间

你想想看,如果窗口 = 间隔,那就是连续扫描,功耗最大,但不会漏包。

如果窗口 < 间隔,那就是间歇扫描,省电,但可能错过广播包。

场景 扫描窗口 扫描间隔 说明
连续扫描(高功耗) 与间隔相同 30ms 不丢包,适合调试
低功耗扫描 30ms 300ms 省电,但可能漏包
平衡模式 100ms 200ms 我常用的配置
小技巧: 广播间隔和扫描窗口要匹配。如果广播间隔是 100ms,扫描窗口至少 50ms 才能保证大概率收到。我曾经因为扫描窗口设得太短(10ms),导致 30% 的广播包被漏掉——排查了一整天。

4.4 被动扫描 vs 主动扫描:别让手机“多嘴”

被动扫描:只收广播包,不发任何请求。

主动扫描:收到广播包后,还会发一个“扫描请求”(SCAN_REQ),设备回复“扫描响应”(SCAN_RSP)。

为什么要注意这个?

我遇到过一个问题:设备广播了关键数据(比如电量),但手机端用被动扫描,永远拿不到扫描响应里的数据。因为被动扫描根本不会触发 SCAN_RSP。

避坑指南:
  • 如果数据放在广播包(Advertising Data)里,被动扫描和主动扫描都能收到。
  • 如果数据放在扫描响应(Scan Response Data)里,必须用主动扫描才能拿到。
  • iOS 系统在后台扫描时默认用被动扫描——这是个大坑,很多开发者不知道。

4.5 广播与扫描的完整流程

下面这张图,是我自己总结的广播扫描交互流程。你看一遍就能明白整个链路。

广播与扫描交互流程图 广播与扫描交互流程 广播设备 扫描设备 广播包(ADV_IND) 扫描请求(SCAN_REQ) 扫描响应(SCAN_RSP) 连接请求(CONNECT_REQ) 说明: 1. 被动扫描:只收广播包,不发 SCAN_REQ 2. 主动扫描:收广播包后发 SCAN_REQ,再收 SCAN_RSP 3. 定向广播:广播包中指定目标设备地址,其他设备忽略

4.6 实战避坑清单

最后,我把自己踩过的坑整理成清单。你写代码前对照一遍,能省不少调试时间。

  1. 广播类型别选错:纯广播用不可连接,需要连接用可连接非定向。
  2. 定向广播只用于回连:别在开放配对场景用,否则新设备连不上。
  3. 扫描窗口别太小:至少是广播间隔的一半,否则漏包严重。
  4. 数据放对位置:关键数据放广播包,不要依赖扫描响应——尤其是 iOS 后台扫描。
  5. 注意 duty cycle 限制:有些芯片在连续扫描时会过热,我遇到过芯片重启的案例。
  6. 广播间隔别太短:20ms 以下可能被蓝牙控制器拒绝,不同芯片行为不同。
一句话总结: 广播是“喊话”,扫描是“听”。喊什么、怎么喊、谁在听、怎么听——这四个问题想清楚,广播扫描就不会出大问题。