BLE背景重新连接

时间:2015-12-15 13:51:11

标签: ios objective-c background cbcentralmanager bluetooth-lowenergy

我希望在用户或系统/后方设备移出设备后,重新连接到BLE设备。

我知道这是可能的: - see this question with description

问题 - 如果应用程序终止,如何设置centralManager以便在后台模式下自动重新连接到外围设备?有人可以逐步描述如何做到这一点吗?

关于当前实施的几点说明:

我使用以下选项创建centralManager:

self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil  options:@{
                                                                                               CBCentralManagerOptionRestoreIdentifierKey: @"myCentralManagerIdentifier",
                                                                                               CBCentralManagerRestoredStatePeripheralsKey : @YES,
                                                                                               CBCentralManagerRestoredStateScanServicesKey : @YES,
                                                                                               CBCentralManagerRestoredStateScanOptionsKey : @YES
                                                                                               }];

之后我开始扫描BLE设备

[self.centralManager scanForPeripheralsWithServices:[self discoverableCharacteristics] options:nil];

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI我连接到外围设备:

    NSString *localName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey];
    [self.centralManager stopScan];
    peripheral.delegate = self;
    [self.centralManager connectPeripheral:peripheral options: @{
                                                                CBConnectPeripheralOptionNotifyOnNotificationKey : @YES
                                                                }];

之后我可以发现服务和特征 - 一切看起来都不错。当我发现特征和读/写数据时cancelPeripheralConnection

在didDisconnect中

我重新连接到设备

- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error
{
    [central connectPeripheral:peripheral options:nil];
}

我还实现了centralManager:willRestoreState:,如:

NSArray *peripherals = dict[CBCentralManagerRestoredStatePeripheralsKey];
for  (CBPeripheral *peripheral in peripherals) {
    [central connectPeripheral:peripheral options:nil];
    peripheral.delegate = nil;
}

在plist中。添加了必需的密钥App communicates using CoreBluetooth

目前,如果我连接到设备并终止它 - 它会自动重新启动并连接到设备 - 一切正常,但如果它再次终止 - 没有任何事情发生。

此外,如果我从外围移出并返回 - 没有任何反应。

更新

关于第5点 - 我的堕落 - 应该将此密钥与connectPeripheral

一起使用 WillRestoreState:

中的

NSArray *peripherals = dict[CBCentralManagerRestoredStatePeripheralsKey];
if (!peripherals.count) {
    peripherals = [central retrievePeripheralsWithIdentifiers:[self discoverableCharacteristics]];
}

if (peripherals.count) {
    for  (CBPeripheral *peripheral in peripherals) {
        [central connectPeripheral:peripheral options:@{
                                                        CBCentralManagerRestoredStatePeripheralsKey : @YES,
                                                        CBCentralManagerRestoredStateScanServicesKey : @YES,
                                                        CBCentralManagerRestoredStateScanOptionsKey : @YES
                                                        }];
         }
} else {
    [self startScanning];
}

当前结果 - 如果未从托盘中滑出,应用将重新启动。我使用我的mac作为外围设备,所以有时当我没有启动应用程序,使外围中心的角色可以连接到mac本身而不是所需的服务。

另一个问题 - 在保持连接失去连接时,重新连接到外围设备是不错的选择:

- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error
{
    [central connectPeripheral:peripheral options:@{
                                                CBCentralManagerRestoredStatePeripheralsKey : @YES,
                                                CBCentralManagerRestoredStateScanServicesKey : @YES,
                                                CBCentralManagerRestoredStateScanOptionsKey : @YES
                                                }];
}

还尝试更改外围设备上的通知特性并在设备上读取它。如果所有都在前台完成 - 所有工作都很完美,但是如果连接在后台完成了某些时候didUpdateValueForCharacteristic根本没有被调用,但didUpdateNotificationStateForCharacteristic被调用而没有错误 - 这意味着(我认为)那个东西在我这边做错了。也许你可以建议问题可以在哪里

还有一个问题 - 将数据写入特征是否存在一些限制?因为在苹果样本中它被设置为20个字节。

1 个答案:

答案 0 :(得分:14)

首先,我想首先说我已经使用CoreBluetooth大约两年了,从我注意到的CoreBluetooth 状态保存和恢复根本不可靠。你可以让它工作得那么“好”,但你永远不会让它可靠地重新连接,除非Apple有一天修复它。

话虽如此,我想在你的设置上注意一些事情。

1)在centralManager:willRestoreState:中,您只能检索应用程序终止时已完成任何通信的外围设备。这意味着您还应该实现centralManagerDidUpdateState:,如果状态为CBCentralManagerStatePoweredOn,那么您可以使用retrievePeripheralsWithIdentifiers:方法检索其他外围设备并重置其委托。这当然意味着您必须在应用程序的某个位置存储外围设备标识符。还记得在这里重置挂起连接。

2)您在centralManager:willRestoreState:中将委托设置为nil!因此,即使它确实连接了,你也不会知道它:P

3)如果应用程序被系统终止,您的应用程序将仅重新启动。如果您从应用程序列表中手动扫描它,它将不会重新启动。不幸的是,如果设备重启,它也不会重新启动。

4)使用蓝牙中央后台模式时不需要CBConnectPeripheralOptionNotifyOnConnectionKey,这对用户来说太烦人了,所以我不会用它。

5)CBCentralManagerRestoredStatePeripheralsKeyCBCentralManagerRestoredStateScanServicesKeyCBCentralManagerRestoredStateScanOptionsKey不是有效的初始化选项,因此我不明白为什么要使用这些选项..

5)如果蓝牙在应用程序终止时切换状态,则所有挂起的连接都将丢失,您将不会重新启动以了解它。这本身就意味着国家恢复是无用的。

总之,我感到非常难过,说出来,但如果你正在开发必须依赖于周边在后台被重新连接的应用程序,然后我尔德不建议这样做。你会感到沮丧。我可能会写一篇关于Apple不想修复的Core Bluetooth中所有错误的文章。更可怕的是,你可以很容易地从一个应用程序破坏设备上全局的蓝牙连接,这样在设备重启之前没有应用程序可以使用蓝牙。这非常糟糕,因为它违反了苹果自己的沙盒原则。

如果您需要更多帮助,请告诉我们!

/ A