iOS蓝牙扫描的坑

一、后台扫描

手机作为中心模式(client):
打开后台模式中的使用蓝牙功能 TARGET→Capabilities→Background Modes→Uses Bluetooth LE accessories(勾选)

二、扫描设备方法

centralManager为蓝牙中心模块

// centralManager.scanForPeripherals(withServices: nil, options: [CBCentralManagerScanOptionAllowDuplicatesKey: true])
centralManager.scanForPeripherals(withServices: nil, options:nil)

三、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数据是怎样合并的?

4.1、经过自己的测试和苹果官方技术支持(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合包的机制为:

  1. iOS收到ADV_IND
  2. iOS发送SCAN_REQ
  3. iOS从缓存中查找SCAN_RSP
  4. 如果有缓存,则将缓存的SCAN_RSP和ADV_IND合并通知App
  5. 如果没有缓存,则直接将ADV_IND通知App
  6. SCAN_RSP的缓存是有时间的,具体时间未知

4.2、由此,会产生一个问题:

当设备的广播数据发生变化(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增加校验,如果是错的数据就丢掉。

五、遇到的坑

  • 坑一:由于苹果的限制,使用第一种方式扫描,APP在后台运行时是扫描不到任何信息的;如果想在后台扫描蓝牙设备,必须使用第二种方式;
  • 坑二:使用第二种方式需要注意,如果设置CBCentralManagerScanOptionAllowDuplicatesKey的值为NO,在后台调用扫描时只能,扫描到一次,即使蓝牙广播的数据有变化,也不会接收到新的广播
  • 坑三:使用第二种方式,即使CBCentralManagerScanOptionAllowDuplicatesKey如果设置为YES,会持续接收到蓝牙发出的广播,但是接收到的蓝牙广播的内容是不会变的;(这里苹果是不推荐我们设置为YES,因为这对手机的电量消耗等是有影响的,但是在某些特定的场景下我们是必须这样做的)
  • 坑四:即使我们使用第二种方式扫描,也设置了CBCentralManagerScanOptionAllowDuplicatesKey为YES,但是如果超过三分钟扫描不到任何蓝牙设备,后台任务一样会停止。

六、建议

由于苹果的这种特性,建议在前台时扫描蓝牙设备时,设置CBCentralManagerScanOptionAllowDuplicatesKey为NO;在后台扫描蓝牙时,设置CBCentralManagerScanOptionAllowDuplicatesKey为YES

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SY.ZHOU

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值