BLE背景重新连接 [英] BLE background reconnect

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

问题描述

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

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

我知道有可能: - < a href =https://stackoverflow.com/q/28813096/2012219>请参阅此问题及说明

I know that it's possible : - see this question with description

问题 - 如何设置 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];

in - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral :( CBPeripheral *)周边广告数据:(NSDictionary *)advertiseData RSSI:(NSNumber *)RSSI 我连接到外围设备:

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
                                                                }];

之后我可以发现服务和特征 - 一切看起来都不错。当我发现特征和读/写数据i 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中。添加了必需的密钥应用程序使用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

in 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];
}

当前结果 - 如果不从托盘中滑出,app将重新启动。我使用我的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 状态保存和恢复根本不可靠。你可以让它工作得那么好,但你永远不会让它可靠地重新连接,除非Apple有一天修复它。

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中将委托设置为nil:willRestoreState:!因此,即使它确实连接,您也不会知道它:我

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) CBCentralManagerRestoredStatePeripheralsKey CBCentralManagerRestoredStateScanServicesKey CBCentralManagerRestoredStateScanOptionsKey 不是有效的初始化选项,所以我不明白为什么要使用这些..

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中所有漏洞的文章。更可怕的是,您可以通过一个应用程序轻松破坏设备上全局的蓝牙连接,这样在设备重启之前,任何应用都无法使用蓝牙。这非常糟糕,因为它违反了苹果自己的沙盒原则。

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天全站免登陆