Core Bluetooth Background Processing for iOS Apps
对于iOS程序,它是至关重要的,它知道你的app是否在前台后者后台运行。一个app后台比前台必须是行为不同的,因为系统资源在一个设备上是有限的。为了整体讨论iOS后台操作,看在 App Programming Guide for iOS 的 Background Execution
默认的,当你的app在后台或者一个暂停的状态的时候在central和peripheral端的许多任务是禁止的。你可以声明app支持核心蓝牙背景执行模式,允许应用程序从一个挂起状态醒来来处理某些Bluetooth-related事件。即使你的应用程序不需要后台处理的全面支持,它仍然可以要求由系统提醒重要事件发生时。
即使您的应用程序支持一个或两个蓝牙核心背景执行模式,它不能一直运行下去。在某种程度上,该系统可能需要终止应用程序,为当前前台app释放内存,导致任何活动或等待连接丢失,例如。在iOS 7,central和peripheral管理者和在app运行时刻状态恢复的蓝牙支持保存状态信息。您可以使用此功能来支持长期的行动涉及到蓝牙设备
Foreground-Only Apps
在大多数iOS app,除非你的请求权限执行指定的后台任务,你的应用过渡到暂停状态后不久进入后台状态。在暂停状态,你的app是不能执行Bluetooth相关的任务,也不知道任何的蓝牙相关事件,除非它回到前台。
在central端, foreground-only apps—app没有声明支持任何Core Bluetooth 后台执行模式的话不能在后台或者暂停状态扫描和发现广播peripheral。在peripheral端,广播是禁止的,和任何的central 尝试获取一个动态的app发布的service的characteristic值是错误的。
根据不同的使用情况下,这种默认行为可以在几个方面影响你的应用程序。作为一个例子,假设你是与你当前连接的peripheral数据交互。现在想象一下,你的应用移动到暂停状态(例如,因为用户切换到另一个应用程序)。如果在你的应用暂停连接到peripheral丢失,你就不会意识到任何断开发生直到应用程序恢复到前台。
Take Advantage of Peripheral Connection Options
所有Bluetooth-related事件发生而foreground-only APP处于暂停状态时由系统排队和交付给应用程序只有在恢复到前台的时候。Core Bluetooth提供一个方法去提醒用户当certain central角色事件发生。用户可以使用这些提醒来决定一个特定事件警告app是否可以回到前台。
你可以利用这些提醒通过包含下面的periphreal连接选项当调用
CBCentralManager类的
connectPeripheral:options:方法取连接一个远程peripheral:
-
CBConnectPeripheralOptionNotifyOnConnectionKey
——包含这个key,如果你想要系统分配一个提醒为给定的peripheral 如果app是暂停的,当一个成功的连接。 -
CBConnectPeripheralOptionNotifyOnDisconnectionKey——包含这个key,如果你想要系统分配一个断开连接的提醒为一个给定的peripheral,如果app在断开的时候是暂停的。
-
CBConnectPeripheralOptionNotifyOnNotificationKey——包含这个Key,如果你想要系统分配一个提醒给所有的通知接收来自给定的Periperhal,如果app在这个事件是暂停的。
关于更多periphreal连接选项的信息,看Peripher Connection Options常量,细节在CBCentralManager Class Reference
Core Bluetooth Background Execution Modes
如果你的app需要运行在后台执行central Bluetooth-related 任务,它必须在 Information property list(Info.plist) 声明支持一个Core Bluetooth 后台执行模式。当你的app声明了这个的时候,当app在暂停的状态的时候允许系统唤醒它处理 Bluetooth-related 事件。这个支持在蓝牙低能量定期提供数据交互是重要的,例如一个心率检测器。
有2个Core Bluetooth后台执行模式在一个app中可以声明,一个是为了apps实现central角色,另一个是为了apps实现periperal角色。如果你的app实现两个角色,它可能声明两个后台执行模式。Core Bluetooth后台执行模式声明通过增加 UIBackgroundModes 在你的Info.plist文件,和设置这个Key的值为一个包含一下字符串之一的数组:
- bluetooth-central——app和蓝牙低能量通信,使用Core Bluetooth 框架
- bluetooth-peripheral——app分享数据,使用Core Bluetooth 框架
Note:属性列表编辑器在Xcode中默认显示为许多人类可读的字符串键,而不是实际的key名。派分实际的Key的名字作为他们出现在Info.plist文件,在编辑窗口点击任何的key和使显示原始的key/Values item 在上下文窗口中。、
关于更多在Info.plist配置内容,看 Xcode Help.
The bluetooth-central Background Execution Mode
当 一个app实现central角色在Info.plist中包含UIBackgroundModes key 用bluetooth-central作为其值,Core Bluetooth framework允许你的app在后台执行某些 Bluetooth-related 任务。你的app在后台能一直发现和连接peripheral,和探索和peripheral数据交互。额外的,系统唤醒你的app在任何CBCentralManagerDelegate 或者CBPeripheralDelegate代理方法是调用,允许你的app处理重要的central角色事件,如建立连接或拆除时,当peripheral发送更新的characteristic值,当一个central管理器的状态改变。
虽然您可以执行许多Bluetooth-related任务应用程序在后台,记住,扫描peripheral而你的应用程序在后台运行时不同于你的app是在前台。特别是,当你的应用程序在后台扫描设备:
-
CBCentralManagerScanOptionAllowDuplicatesKey
扫描选项是忽略的,和多个发现广播的peripheral被合并成一个单一的发现事件。 -
如果所有的app是在后台扫描peripheral,central设备扫描的间隔增加广播包。因此,它可能需要更长的时间来发现一个广告peripheral。
这些变化帮助最小化电台使用和提高你的iOS设备的电池寿命。
The bluetooth-peripheral Background Execution Mode
在后台执行某些peripheral角色任务,你必须在你的app的Info.plist中包括 UIBackgroundModes key 和bluetooth-peripheral 作为其值。当key-value配对的包含在app的Info.plist文件时,系统唤醒你的app进程去读取,写入,和订阅事件。
额外的允许你的app从连接的centrals唤醒处理读取,写入,和订阅请求。Core Bluetooth framework允许你的app在后台状态广播。你应该注意你的应的应用程序在后台运行时广播不同于你的app是在前台。特别是,当你的应用程序在后台广播:
- CBAdvertisementDataLocalNameKey 官博key是忽略的,和本地的peripheral的名字是不广播的。
- 所有service UUUIDs包含的在放置在一个特殊的“溢出”区域的CBAdvertisementDataServiceUUIDsKey 广告的key value;他们可以发现只有一个iOS设备显式扫描
- 如果所有的app是在后台广播,你的periperal设备的频率发送广播数据包可能会减少。
Use Background Execution Modes Wisely
虽然声明应用程序来支持一个或两个Core Bluetooth 前台执行模式可能需要实现一个特定的用例,你应该总是负责人的执行后台进程。因为执行许多Bluetooth-related任务需要的积极使用iOS设备的机载电台和,反过来,无线电使用在iOS设备电池寿命上有不良影响,试着减少你的后台工作量。应用唤醒任何Bluetooth-related事件应该尽快处理并返回,这样应用程序可以暂停一次。
任何应用程序声明支持Core Bluetooth 后台执行模式必须遵循一些基本原则:
- 应用程序应该会话建立和提供一个接口,允许用户决定何时启动和停止Bluetooth-related事件的交付。
- 被吵醒后,应用程序有大约10秒完成一个任务。理想情况下,应该尽可能快地完成这个任务,让自己再次暂停。应用程序花太多的时间在后台执行可以限制系统或死亡。
- 应用程序不应该使用被叫醒为机会,执行附加任务无关的为什么叫醒了应用系统。
关于应该如何表现你的应用的一般信息在后台状态,看 Being a Responsible Background App in App Programming Guide for iOS.
Performing Long-Term Actions in the Background
某些app可能需要使用Core Bluetooth framework在后台执行长期的活动。例如,假设你开发一个家庭安全app为iOS 设备和门的锁通信(配备蓝牙低能量技术)。app和锁交互当用户离开家自动锁住,当用户回来自动解锁,app的操作都是在后台。当用户厉害家,iOS 设备可能最终超出锁的范围,导致到锁的连接丢失。在这一点上,应用程序可以简单地调用CBCentralManager类的方法connectPeripheral:options:,因为连接请求不超时,iOS设备将重新连接当用户返回家里。
现在假设用户离家几天。如果应用程序终止系统用户不在时,应用程序将无法重新连接锁当用户返回家里,和用户可能无法打开门。对于这样的应用程序来说,这是至关重要的能够继续使用Core Bluetooth执行长期的行为,如监测活动和挂起的连接。
State Preservation and Restoration
因为保存和恢复的状态是建立在Core Bluetooth,应用程序可以选择这个功能要求系统保存你的app的 central和peripheral 管理者和继续执行特定Bluetooth-related任务的状态,即使应用程序不再运行。当其中一个任务完成,系统重新运行你的应用在背台和使你的应用程序有机会恢复其状态并适当地处理事件。在上面描述的家庭安全app的情况下,系统会监控连接请求,和重新运行app处理centralManager:didConnectPeripheral:代理回调,当用户回到家时和连接请求完成。
Core Bluetooth 支持保存状态和恢复状态为你的app实现central角色,peripheral角色,或者两个都实现。当你的app实现central角色和为保存和恢复状态增加支持,系统保存central管理者的状态,当系统终止你的app,释放内存(如果你的app已经有多个central管理者,你可以选择你想要的一个系统保持联系)。在实际中,为了给CBCentralManager对象与系统保持联系:
- central管理器在扫描services(和任何扫描选项指定扫描开始时)
- central管理器试图连接到或已经连接peripheral
- central管理者的characteristics已经订阅
应用程序实现peripheral角色同样可以利用保存和恢复状态。为了CBPeripheralManager对象和系统保持联系:
- peripheral 管理者已经广播数据
- peripheral 管理者已经发布services和characteristics 到设备的数
- central 已经订阅你的characteristics值
当你的app通过系统重新 运行在后台(因为你的app已经在搜索peripheral,例如),你能重新实例化你的app的central 管理者 和peripheral 管理者和恢复他们的状态。下一节详细描述了如何利用保存和恢复状态在你的应用。
Adding Support for State Preservation and Restoration
保存和恢复状态在Core Bluetooth是一个可选的特性和需要帮助从你的应用程序的工作。您可以添加支持此功能在你的应用程序遵循下面这个过程:
-
在保存和恢复状态选项,当你alloc和init一个central管理者 或者 一个peripheral
管理者对象,这一步是藐视在保存和恢复的选项。 -
重新实例化任何central 管理者对象或者peripheral 管理者对象之后,系统让你的app重新运行。这一步在 Reinstantiate Your Central and Peripheral Managers
-
实现适当的恢复代理方法。这一步在 Implement the Appropriate Restoration Delegate Method 描述,
-
更新你的central管理者和peripheral管理者的初始化进程。这一步在 Update Your Initialization Process 描述。
Opt In to State Preservation and Restoration
在保存和恢复特点选项,简单的提供一个唯一的恢复标识符当你alloc和init一个central 或者peripheral 管理者。恢复标识符是一个字符串,在你的app的Core Bluetooth标识central 或者peripheral管理者。字符串的值是重要的代码,但这个字符串的存在告诉Core Bluetooth ,它需要保存的状态标记对象。Core Bluetooth保存的状态,那些对象只有一个恢复标识符。
例如,在保存和恢复状态选项app只使用一个CBCentralManager
对象实例实现central角色,指定CBCentralManagerOptionRestoreIdentifierKey初始化选项并提供一个恢复标识符为central 管理者当你alloc 和init 它。
myCentralManager =
[[CBCentralManager alloc] initWithDelegate:self queue:nil
options:@{ CBCentralManagerOptionRestoreIdentifierKey:
@"myCentralManagerIdentifier" }];
虽然上面的例子不能证明这一点,你app在保存和恢复状态选项使用peripheral管理器对象以类似的方式:指定CBPeripheralManagerOptionRestoreIdentifierKey初始化选项,并提供恢复标识符,当你alloc和init每一个peripheral 管理者对象
Note:因为app可以有多个CBCentralManager 和 CBPeripheralManager对象实例,确保每一个恢复标识符是唯一的,这样系统可以正确区分一个central(或peripheral)管理者对象。
Reinstantiate Your Central and Peripheral Managers
当系统使你的app重新在后台运行,第一件事你需要重新实例化合适的central和peripheral管理者和相同的恢复标识符作为他们第一次创建。如果你的app只使用一个cnetral或者 peripheral管理者,管理者会和你的app的生命周期退出,你在这步不需要做任何事情。
如果您的应用程序使用一个以上的peripheral或central管理者或如果它使用一个管理者,不是在你的应用程序的生命周期,应用程序需要知道哪些管理者重新实例化,当系统使它重新运行。您可以访问所有系统保存的管理者的恢复标识符的列表,当它是终止的时候,使用合适的运行选项key (UIApplicationLaunchOptionsBluetoothCentralsKey
或者UIApplicationLaunchOptionsBluetoothPeripheralsKey)当实现你的app 代理的 application:didFinishLaunchingWithOptions:方法。
例如:当系统使你的app重新运行,你能检索所有的app中系统保存的central管理者的恢复标识符,像这样:
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSArray *centralManagerIdentifiers =
launchOptions[UIApplicationLaunchOptionsBluetoothCentralsKey];
...
你有恢复标识符列表之后,通过它简单的循环和重新实例化适当的central管理者对象
当你的app重新运行的时候,系统只为正在执行某些Bluetooth-related 任务的central和peripheral管理者提供恢复标识符(而你的app不在运行)。运行选项key的更多描述细节在 UIApplicationDelegate Protocol Reference
Implement the Appropriate Restoration Delegate Method
当你已经重新初始化适当的central和peripheral管理者在你的app,恢复他们通过同步状态与蓝牙系统的状态,将你app加速和系统在做什么,你必须实现适当的恢复代理。为central 管理者实现 centralManager:willRestoreState: 代理方法,为peripheral 管理者,实现 peripheralManager:willRestoreState: 代理方法
Import:为app在保存和恢复状态选项,有第一个方法(centralManager:willRestoreState: and peripheralManager:willRestoreState:)调用,当你的app重新运行在后台去完成一些蓝牙相关任务。app没有在保存状态(或者没有恢复运行),相反的, centralManagerDidUpdateState: 和 peripheralManagerDidUpdateState: 代理方法被调用。
上面的两个代理方法,最后一个参数是一个字典,包含管理者在app已经终止是的保存的信息。对于这个有用的字典Key,看Central Manager State Restoration Options constants in CBCentralManagerDelegate Protocol Reference
和 Peripheral_Manager_State_Restoration_Options constants in CBPeripheralManagerDelegate Protocol Reference.
CBCentralManager对象的恢复状态,使用字典中的key在 centralManager:willRestoreState: 代理方法提供。例如,如果你的central 管理者 对象 有任何的活动或者等待连接在一个的app终止的时候,系统继续检测它们在你的app代表。以下演示,你能使用 CBCentralManagerRestoredStatePeripheralsKey 字典key得到所有的central 管理者已经连接或尝试连接的peripheral 列表:
- (void)centralManager:(CBCentralManager *)central
willRestoreState:(NSDictionary *)state {
NSArray *peripherals =
state[CBCentralManagerRestoredStatePeripheralsKey];
...
你所做的与恢复peripheral的列表在上面的例子中根据用例。例如,如果你的app保持一个central 管理者发现列表,你可能想要恢复peripheral添加到列表引用它们。 Connecting to a Peripheral Device After You’ve Discovered It 描述,一定要设置一个peripheral的代理,以确保它得到适当的回调。
你可以恢复CBPeripheralManager对象的状态以类似的方式使用字典的key提供在peripheralManager:willRestoreState:代理方法。
Update Your Initialization Process
你已经实现前面三个请求步骤之后,你可能想看看更新你的central和peripheral 管理者的初始化过程。虽然这是一个可选的步骤,它可以是重要的在你的应用确保事情顺利进行。例如,应用程序可能被终止,而它在一个连接的peripheral中探索数据。当你的应用程序恢复periphreal,它不知道发现了多远它才终止。你要确保你从你离开发现过程开始。
例如:当初始化你的app在 centralManagerDidUpdateState: 代理方法,你会发现如果你成功地发现了一个特定的恢复的peripheral 的service(应用程序终止之前),像这样:
NSUInteger serviceUUIDIndex =
[peripheral.services indexOfObjectPassingTest:^BOOL(CBService *obj,
NSUInteger index, BOOL *stop) {
return [obj.UUID isEqual:myServiceUUIDString];
}];
if (serviceUUIDIndex == NSNotFound) {
[peripheral discoverServices:@[myServiceUUIDString]];
...
上面的例子演示,如果系统终止你的app在它结束发现service之后,开始探索恢复的peripheral的数据通过调用 discoverServices:. 。如果你的app发现service成功,然后,您可以检查是否适当的characteristic被发现(以及是否你已经订阅)。以这种方式通过更新您的初始化过程,你会确保你在正确的时间正确的方法。