BLE后台重连 [英] BLE background reconnect

查看:31
本文介绍了BLE后台重连的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在设备被用户或系统移出/终止/在后台模式下重新启动后重新连接到 BLE 设备.

I want to reconnect to BLE device after device is moved out/terminated by user or system/reboted in background mode.

我知道这是可能的:-查看这个问题的描述

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

Question - How can i setup centralManager for automatically reconnect to peripheral in background mode if app was terminated? Can someone describe step-by-step how it can be done?

关于当前实现的几句话:

Few word about current implementation:

我使用以下选项创建 centralManager:

I create centralManager with options like:

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

之后我开始扫描 BLE 设备

After that i start to scan for BLE device

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

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

in - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI i connect to peripheral:

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

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

After that i can discover services and characteristics - all looks like ok. When i discover characteristic and read/write data i cancelPeripheralConnection

在 didDisconnect 中我重新连接到设备

in didDisconnect i reconnect to device

- (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 使用 CoreBluetooth 进行通信.

In plist. added required key App communicates using CoreBluetooth.

目前,如果我连接到设备并终止它 - 它会自动重新启动并连接到设备 - 一切正常,但如果它再次终止 - 什么都没有发生.

Currently if i connected to device and terminate it - it relaunch automatically and connect to device - all it's ok, but if it's terminated again - nothing is happening.

另外,如果我从外围设备移出然后回来 - 什么也没发生.

Also if i moved out from peripheral and that come back - nothing happened.

更新

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

regarding point 5 - my fall - should use this key with 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 本身而不是所需的服务.

Current result - app will relaunched if it not swiped out from tray. I use my mac as a peripheral, so some times when i not launch app that make role of peripheral central can connect to mac itself not to required service.

另一个问题 - 在失去连接的情况下重新连接到外围设备是否是一个不错的选择以保持连接,例如:

Another question - are it's good option to reconnect to peripheral while lost connection for keeping connection like:

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

还尝试更改外围设备上的通知特性并在设备上读取它.如果一切都在前台完成 - 一切都很完美,但如果连接是在后台完成的,有时 didUpdateValueForCharacteristic 根本没有被调用,但 didUpdateNotificationStateForCharacteristic 被调用且没有错误 - 这意味着(我认为)我身边做错了什么.也许你可以建议问题可能在哪里

Also try to change notify characteristic on peripheral and read it on device. If all done in foreground - all works perfect, but in case connection was done in background some times didUpdateValueForCharacteristic not called at all, but didUpdateNotificationStateForCharacteristic is called with no error - this mean (i think) that something was done wrong by my side. Maybe u can advice where problem can be

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

And one more question - is there is some restriction in writing data to characteristics? because in apple sample it's setuped to 20 bytes.

推荐答案

首先我想说我已经使用 CoreBluetooth 大约两年了,从我注意到 CoreBluetooth 状态保存和恢复 根本无法可靠地工作.你可以让它正常"地工作,但除非苹果有一天修复它,否则你永远无法让它可靠地重新连接.

First off I wanna start by saying that I have been working with CoreBluetooth for about two years now and from what I have noticed CoreBluetooth State Preservation and Restoration does not work reliably at all. You can get it working sort of "ok", but you will never get it to reconnect reliably unless Apple fixes it some day.

话虽如此,我想在您的设置中注意几点.

Having said that, I want to note a few things on your setup.

1) 在 centralManager:willRestoreState: 中,您只能检索在应用程序终止时进行过任何通信的外围设备.这意味着您还应该实现 centralManagerDidUpdateState: 并且如果状态是 CBCentralManagerStatePoweredOn 那么您可以使用 retrievePeripheralsWithIdentifiers: 方法来检索其他外围设备和也重置他们的代表.这当然意味着您必须将外围标识符存储在应用程序的某个地方.还记得在这里重置挂起的连接.

1) In centralManager:willRestoreState: you can only retrieve peripherals that has done any communication while the app was terminated. This means that you should also implement centralManagerDidUpdateState: and if the state is CBCentralManagerStatePoweredOn then you can use the retrievePeripheralsWithIdentifiers: method to retrieve the other peripheral and reset their delegate as well. This of course means that you have to stor the peripheral identifiers somewhere in your app somewhere. Also remember to reset pending connections here as well.

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

2) You set the delegate to nil in centralManager:willRestoreState:! So even if it does connect then you will not know about it i:P

3) 只有当应用程序被系统终止时,您的应用程序才会重新启动.如果您从应用程序列表中手动滑动杀死它,它将不会重新启动.不幸的是,如果设备重新启动,它也不会重新启动.

3) Your app will only get relaunched if the app was terminated by the system. It will not get relaunched if you manually swipe-kill it from the application list. Neither will it get relaunched if the device is rebooted, unfortunately.

4) CBConnectPeripheralOptionNotifyOnConnectionKey 在使用蓝牙中央后台模式时不是必需的,只是对用户来说很烦人,所以我不会使用它.

4) The CBConnectPeripheralOptionNotifyOnConnectionKey is not necessary when using the bluetooth-central background mode and is just annoying for a user so I would not use it.

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

5) CBCentralManagerRestoredStatePeripheralsKey, CBCentralManagerRestoredStateScanServicesKey, CBCentralManagerRestoredStateScanOptionsKey are not valid initialisation options so I don’t get why you are using those..

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

5) If the bluetooth switches state while the app is terminated then all pending connections will be lost and you will not be relaunched to know about it. This on its own effectively means that State Restoration is rather useless.

无论如何,我很难过,但如果您正在开发一个必须依赖在后台重新连接外围设备的应用程序,那么我不建议您这样做.你会感到沮丧.我可能会写一篇关于 Apple 不想修复的 Core Bluetooth 中的所有错误的文章.更可怕的是,您可以很容易地通过一个应用程序破坏设备上的全局蓝牙连接,因此在设备重新启动之前没有应用程序可以使用蓝牙.这很糟糕,因为它违反了 Apple 自己的沙盒原则.

Anyhow, I am sad to say it, but if you are developing an app that must rely on the peripheral being reconnected in the background then I wold not recommend doing it. You will be frustrated. I could probably write an essay about all the bugs in Core Bluetooth that Apple does not want to fix. Even more frightening is that you can pretty easily ruin the bluetooth connectivity globally on the device from one single app so that no app can use bluetooth until the device is rebooted. This is pretty bad since it goes against Apples own Sandboxing principle.

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

If you need any more help, just let me know!

/A

这篇关于BLE后台重连的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆