概要
默认情况下当App处于后台/挂起状态之后,所有BLE相关的操作将不可用,也接收不到任何BLE事件通知,直到该App恢复到前台运行为止。
针对App需要在后台/挂起的状态下执行BLE相关任务的场合,CoreBluetooth提供了以下2种方案:
利用Peripheral连接选项触发系统通知
该方案为处于后台/挂起状态的App提供了一个切换到前台来处理BLE事件的窗口,但需要用户授权。当接收到来自Peripheral的事件后,CoreBluetooth会以系统通知来的方式询问用户是否需要切换到处于后台的App来处理该事件。如果用户不同意,App仍将处于后台挂起状态,无法处理来自Peripheral设备的事件。该方案仅适用于Central角色,不要求App具备任何后台运行权限。
实现方式
在调用CBCentralManager的connectPeripheral:options:函数与Peripheral设备建立连接的时候,以Key-Value形式传入以下参数到options中:
CBConnectPeripheralOptionNotifyOnConnectionKey - Bool值,Yes为启用,默认为No。启用后当App处于挂起状态时,iOS系统将在每次与Peripheral设备【建立】连接后触发系统通知。
CBConnectPeripheralOptionNotifyOnDisconnectionKey - Bool值,YES为启用,默认为No。启用后当App处于挂起状态时,iOS系统将在每次与Peripheral设备【断开】连接后触发系统通知。
CBConnectPeripheralOptionNotifyOnNotificationKey - Bool值,Yes为启用,默认为No。启用后当App处于挂起状态时,iOS系统将为所有来自Peripheral的事件触发系统通知。
系统限制
如果当前系统内有多个App都以相同的选项连接了相同的Peripheral设备,在用户收到系统通知并同意之后,只有最后一个处于前台运行的App将会被切换到前台运行。
利用CoreBluetooth后台运行模式
在CoreBluetooth框架中Central和Peripheral角色的App均可以通过申请对应的后台运行模式,从而能够在后台运行BLE相关的任务。
Central角色
所需申请的后台运行模式:
- bluetooth-central (Uses Bluetooth LE accessories)
当App处于后台运行时可以执行下列BLE相关的任务:
- 发现Peripheral设备
- 管理Peripheral设备连接
- 读写和订阅Peripheral数据
- 发送Notification或者Indication到Peripheral
- 处理CBCentralManagerDelegate上的事件
- 处理CBPeripheralDelegate上的事件
当App处于挂起状态后系统会唤醒App来处理CBCentralManagerDelegate或者CBPeripheralDelegate上的事件,如果此时App进程已经被系统终止,CoreBluetooth会重启App。
当App处于后台运行时Peripheral扫描操作会有如下限制:
- 代码中设置的扫描选项CBCentralManagerScanOptionAllowDuplicatesKey的值将会被忽略,强制为NO。
- 同时有多个App在后台模式扫描Peripheral的场合,对Peripheral广播的扫描间隔会增加,导致发现Peripheral设备的时间增加。
Peripheral角色
所需申请的后台运行模式:
- bluetooth-peripheral (Acts as a Bluetooth LE accessory)
当App处于后台运行可以执行下列BLE相关的任务:
- 发送Peripheral广告
- 处理来自Central的数据读写和订阅请求
当App处于挂起状态后系统会唤醒App来处理数据读写和订阅请求,如果此时App进程已经被系统终止,CoreBluetooth会在后台重启App。
当App处于后台运行时对Peripheral广告会有如下限制:
- CBAdvertisementDataLocalNameKey将会被忽略,Peripheral的本地名称将为空。
- CBAdvertisementDataServiceUUIDsKey中的所有服务UUID将会被放到overflow区域,此时Central在搜索服务时必须指定服务UUID才能发现对应的服务
- 同时有多个App在后台模式扫发送Peripheral广告的场合,每个广告之间的间隔时间会增加,导致Peripheral被发现的时间增加。
CoreBluetooth的状态保存与恢复
退至后台的App不能保证一直处于挂起状态,在系统资源紧张的时候App进程会被终止掉以释放内存。
虽然CoreBluetooth会重新启动App进程,但为接下来能正确执行BLE任务,以下数据需要正确恢复到进程终止前的状态:
CBCentralManager
- 正在扫描的服务以及对应的扫描选项
- 正在连接或者已经连接的Peripheral设备
- 订阅了的characteristics
CBPeripheralManager
- 正在广告的数据
- 发布了的服务和characteristics
- 订阅了characteristics的Central设备
实现细节
CoreBluetooth已经提供了CBCenteralManager和CBPeripheralManager状态保存与恢复的API,需要实现以下步骤方可正常使用:
启用实例状态恢复 (必要步骤)
在调用CBCentralManager/CBPeripheralManager initWithDelegate: queue: options:函数初始化实例时,以Key-Value形式将下列参数传入options中:
1
2CBCentralManagerOptionRestoreIdentifierKey(CBCentralManager)
CBPeripheralManagerOptionRestoreIdentifierKey(CBPeripheralManager)
参数值为NSString类型,作为保存和恢复状态时唯一识别实例的ID。如果有多个实例,应该为为每个实例分配不同的ID。
重新创建实例 (必要步骤)
在App重启时在通过下列Key值可以从UIApplicationDelegate application:didFinishLaunchingWithOptions:事件处理函数的options参数中能够获取到需要恢复的实例ID列表。
1
2UIApplicationLaunchOptionsBluetoothCentralsKey(CBCentralManager)
UIApplicationLaunchOptionsBluetoothPeripheralsKey(CBPeripheralManager)如果存在多个启用了状态恢复的CBCentralManager/CBPeripheralManager实例,CoreBluetooth只会将需要执行后台BLE任务的实例ID放入次列表中。
在初始化新建CBCentralManager/CBPeripheralManager实例的时候将列表中对应的ID作为options参数传入。
恢复实例状态 (必要步骤)
在CBCenteralManagerDelegate centralManager:willRestoreState函数中,可以通过下列的KEY从state参数中获取需要恢复的的CBCentralManager状态数据
1
2
3CBCentralManagerRestoredStatePeripheralsKey - 获取CBPeripheral列表,其中包含了App进程终止时连接上或者处于连接中的Peripheral设备
CBCentralManagerRestoredStateScanServicesKey - 获取CBUUID列表,其中包含了App进程终止时正在扫描的服务UUIDCB
CentralManagerRestoredStateScanOptionsKey - 获取NSDictionary实例,其中包含了App进程终止时正在使用的Peripheral扫描选项
在CBPeripheralManagerDelegate peripheralManager:willRestoreState:函数中,可以通过下列的KEY从state参数中获取需要恢复的CBPeripheralManager状态数据
1
2
CBPeripheralManagerRestoredStateServicesKey - 获取CBMutableService列表,其中包含了App进程终止时已经发布的服务
CBPeripheralManagerRestoredStateAdvertisementDataKey - 获取NSDictionary实例,其中包含了App进程终止时正在发送的Peripheral广告
同步任务状态 (可选步骤)
当App进程被终止的时候,可能存在尚未结束的BLE任务,例如读取Peripheral的数据或者扫描Peripheral设备。上述的BLE任务在被CoreBluetooth执行完后会更新到恢复数据中,在下列事件处理函数中能够从恢复数据获取最新的状态:
1
2CBCentralManagerDelegate centralManagerDidUpdateState:
CBPeripheralManagerDelegate peripheralManagerDidUpdateState:
使用iOS后台模式的原则
- 避免过于频繁的执行后台任务,从而减小对电池续航时间的影响。
- 当App在后台被唤醒后应该尽快(10s内)完成处理后返回,避免执行与本次该唤醒无关的任务,从而能让App尽快回到挂起状态。
- 单次执行时间过长的后台任务存在被系统降缓执行甚至直接终止进程的风险。
- 对于需要长期在后台模式工作的App,需要充分考虑App进程被系统终止后重启的场景,做好任务状态的保存和恢复,并尽量优化后台启动流程,较少不必要的资源开销。
- 受iOS系统限制,所有的后台模式都无法唤醒被用户强制关闭的App(在多任务管理界面划掉)。
官方资料