iOS BLE Scan

iOS扫描BLE设备的方法

iOS在使用CoreBluetooth框架进行BLE开发时,通常作为中心设备(Master角色)存在,扫描并连接BLE从设备。
搜索的方法很简单,只需要调用- (void)scanForPeripheralsWithServices:(nullable NSArray *)serviceUUIDs options:(nullable NSDictionary *)options;接口,然后等待系统回调上报就可以。

BLE 扫描流程

从调用iOS的scan接口,到收到系统回调,这中间其实有下面几步的交互:

  1. BLE设备端发送广播ADV_IND
  2. iOS手机端收到广播后,向该BLE设备发送SCAN_REQ
  3. BLE设备端收到SCAN_REQ后,发送广播SCAN_RSP
  4. iOS将ADV_IND和SCAN_RSP合包后,通过系统回调通知调用者

如下图所示:

iOS与设备的扫描交互

按照蓝牙协议,这几个步骤是分开的,只不过iOS底层帮我们合并了而已。下面我们考虑这几个问题:

  1. iOS收到设备端发出的ADV_IND之后,是不知道还有没有更多数据的,那么SCAN_REQ的发送机制是怎样的呢?
  2. iOS发出SCAN_REQ后,并不知道会不会有SCAN_RSP,那么是怎样处理的?
  3. ADV_IND和SCAN_RSP数据是怎样合并的?

经过自己的测试和苹果官方技术支持(code-level support)的沟通,初步有以下结论:

  1. 如果App在前台,iOS会处于主动搜索模式,在此情况下,iOS会尽可能的在收到ADV_IND后发送SCAN_REQ,这里说尽可能的原因,是因为按照苹果官方技术支持的说法,iOS会发送SCAN_REQ,但根据自己抓包显示,有时候iOS会收到几包ADV_IND后才会发送SCAN_REQ
  2. 如果App进入后台,iOS会进入被动搜索模式,此时,iOS会缓存SCAN_RSP,并会降低SCAN_REQ的发送频率,即可能几包ADV_IND后才会发送一包SCAN_REQ,此时iOS会将收到的ADV_IND和缓存的SCAN_RSP合包告诉调用者。
  3. 根据实际测试结果,发现App在前台时也会有使用SCAN_RSP缓存的情况。从而推测,iOS将ADV_IND和SCAN_RSP合包的机制为:
    3.1 iOS收到ADV_IND
    3.2 iOS发送SCAN_REQ
    3.3 iOS从缓存中查找SCAN_RSP
    3.4 如果有缓存,则将缓存的SCAN_RSP和ADV_IND合并通知App;如果没有缓存,则直接将ADV_IND通知App
    3.5 SCAN_RSP的缓存是有时间

由此,会产生一个问题:当设备的广播数据发生变化(ADV_IND和SCAN_RSP都产生变化),iOS可能会上报一个新的ADV_IND数据和老的SCAN_RSP数据。造成数据错乱。但当SCAN_RSP更新后,数据就可恢复正常,通常收到1-3包ADV_IND数据后可恢复正常

如:
BLE设备一直在广播

    SCAN_RSP = 3f
    ADV_IND = 3f

iOS此时向App广播的数据也是

    SCAN_RSP = 3f
    ADV_IND = 3f

此时,BLE设备广播发生变化,广播数据变为

    SCAN_RSP = 42
    ADV_IND = 42

App在收到广播包变化的第一个系统回调通常为

    SCAN_RSP = 3f  //老的SCAN_RSP
    ADV_IND = 42    //新的ADV_IND

然后,App通常会在收到1-3个系统回调后变为正常,这个取决于SCAN_RSP的更新时间,所以具体什么时候数据能恢复正常是不确定的,1-3包只是经验值。

所以,如果你的BLE设备的广播数据会发生变化,那么是需要考虑数据错乱问题的。可以对ADV_IND+SCAN_RSP增加校验,如果是错的数据就丢掉。

你可能感兴趣的:(iOS BLE Scan)