使用CoreBluetooth.framework的应用可以在后台运行。需要在info.plost文件中增加bluetooth-Central和bluetooth-peripheral键.
以下介绍iOS(iOS7)在后台BLE持续连接外围设备的开发步骤。
步骤简述
基本步骤是:
创建项目,设置plist
实现delegate方法,判断蓝牙状态,如成功则扫描指定UUID设备(如不指定UUID,则无法后台持续连接)
实现delegate方法,当发现指定设备后,连接该设备
实现delegate方法,当连接指定外围设备成功,编写定时器,每秒读取1次RSSI
实现delegate方法,当监听到失去和外围设备连接,重新建立连接
实现delegate方法,当读取到RSSI值,打印出它的值
创建项目,设置plist
创建一个Single View Application即可。
项目引入CoreBlue.framework。
代码中:
1
import <CoreBluetooth/CoreBluetooth.h>
让ViewController实现相应的delegate:
1
@interface ViewController () <CBCentralManagerDelegate, CBPeripheralDelegate>
下面就是实现delegate相关方法了。
判断蓝牙状态
代码:
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
DLog();
if (central.state == CBCentralManagerStatePoweredOn) {
[self.centralManger scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:@"f3d9"]]
options:nil];
}
}
其中f3d9是我连接到iPad mini2的LightBlue app模拟的BLE外围设备,你要换成你设备的UUID。
或者不设置具体的UUID:
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
DLog();
if (central.state == CBCentralManagerStatePoweredOn) {
[self.centralManger scanForPeripheralsWithServices:nil
options:nil];
}
}
貌似这样也可以,但是运行几分钟后,会出现类似这样的报错:
1
2014-01-02 11:10:40.799 BLEBackgroundMode[6961:60b] CoreBluetooth[WARNING] <CBPeripheral: 0x15d914a0 identifier = 730CF80B-90F6-C55C-3FB5-66326BDA453A, Name = "iPad", state = connecting> is not connected
发现指定设备后连接该设备
代码:
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
DLog(@"peripheral name %@ id %@ rssi %d", peripheral.name, peripheral.identifier, [RSSI integerValue]);
self.peripheral = peripheral;
[self.centralManger connectPeripheral:peripheral options:nil];
}
这里要注意,将peripheral对象设置给成员变量,保持对这个对象的引用,否则会因为没有引用计数而被回收。
连接指定外围设备后启动读取RSSI定时器
代码:
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
DLog();
self.peripheral.delegate = self;
if (!self.timer) {
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(readRSSI)
userInfo:nil
repeats:1.0];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
}
}
这里创建了定时器(NSTimer),每间隔1秒读取1次RSSI,如果读到了就会触发peripheral的delegate方法,下面会说。
因为这个方法是iOS系统调用的,因此Timer是通过runloop跑在系统线程中的。
失去和外围设备连接后重建连接
代码:
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
[self.centralManger connectPeripheral:peripheral options:nil];
}
这个方法是必须实现的,因为我监控到,我的iPhone4S(Central)连接iPad mini2(Peripheral)大约每10秒钟就会中断连接,正好触发这个方法重建连接。
重建连接可能造成数秒后才能读取到RSSI。
读取到RSSI值后的操作
代码:
- (void)peripheralDidUpdateRSSI:(CBPeripheral *)peripheral error:(NSError *)error
{
if (!error) {
NSLog(@"rssi %d", [[peripheral RSSI] integerValue]);
}
}
这个方法读取到RSSI值,本示例中,基本上每秒读取到1次。
存在的问题
需要进一步测试,比如跑其他大应用,系统是否会停止BLE连接,这方面是否需要保持状态。