我希望在用户或系统/后方设备移出设备后,重新连接到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
我重新连接到设备
- (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个字节。
答案 0 :(得分:14)
首先,我想首先说我已经使用CoreBluetooth大约两年了,从我注意到的CoreBluetooth 状态保存和恢复根本不可靠。你可以让它工作得那么“好”,但你永远不会让它可靠地重新连接,除非Apple有一天修复它。
话虽如此,我想在你的设置上注意一些事情。
1)在centralManager:willRestoreState:
中,您只能检索应用程序终止时已完成任何通信的外围设备。这意味着您还应该实现centralManagerDidUpdateState:
,如果状态为CBCentralManagerStatePoweredOn
,那么您可以使用retrievePeripheralsWithIdentifiers:
方法检索其他外围设备并重置其委托。这当然意味着您必须在应用程序的某个位置存储外围设备标识符。还记得在这里重置挂起连接。
2)您在centralManager:willRestoreState:
中将委托设置为nil!因此,即使它确实连接了,你也不会知道它:P
3)如果应用程序被系统终止,您的应用程序将仅重新启动。如果您从应用程序列表中手动扫描它,它将不会重新启动。不幸的是,如果设备重启,它也不会重新启动。
4)使用蓝牙中央后台模式时不需要CBConnectPeripheralOptionNotifyOnConnectionKey
,这对用户来说太烦人了,所以我不会用它。
5)CBCentralManagerRestoredStatePeripheralsKey
,CBCentralManagerRestoredStateScanServicesKey
,CBCentralManagerRestoredStateScanOptionsKey
不是有效的初始化选项,因此我不明白为什么要使用这些选项..
5)如果蓝牙在应用程序终止时切换状态,则所有挂起的连接都将丢失,您将不会重新启动以了解它。这本身就意味着国家恢复是无用的。
总之,我感到非常难过,说出来,但如果你正在开发必须依赖于周边在后台被重新连接的应用程序,然后我尔德不建议这样做。你会感到沮丧。我可能会写一篇关于Apple不想修复的Core Bluetooth中所有错误的文章。更可怕的是,你可以很容易地从一个应用程序破坏设备上全局的蓝牙连接,这样在设备重启之前没有应用程序可以使用蓝牙。这非常糟糕,因为它违反了苹果自己的沙盒原则。
如果您需要更多帮助,请告诉我们!
/ A