I'm working on an app that connects to a peripheral via CoreBluetooth.
It uses state restoration to retrieve a previously connected peripheral and tries to connect to it with CBCentralManager's connect(_:options:) function.
This works quite well, but sometimes the connection between both devices just stop to work. CBCentralManagerDelegate methods centralManager(_:didConnect:) or centralManager(_:didFailToConnect:error:) never get called although the peripheral is nearby.
The only solution to get out of this broken state is to forget the peripheral in the Bluetooth system settings and to bond both devices again.
Did anyone ever experience something similar?
Things that don't work:
Rebooting the iPhone
Toggling bluetooth in the system settings
Removing the state restoration
Updating to the latest iOS version (16.2)
Related
I have an app that uses Bluetooth (BLE). All BLE communication works fine. State restoration is also implemented and works well. The app has automatic re-connection implementation: whenever the CBError.peripheralDisconnected error occurs, the app tries to reconnect to the peripheral by calling cbCentralManager.connect(cbPeripheral).
Since iOS 15/16 there is a problem. Let's assume that the app is connected to a specific BLE device. I turn off the device (at this moment the automatic re-connection started) and move the app to the background. After several hours (e.g. over the night) I turn on the BLE device and the connection isn't established. I can see this on my Bluetooth device and in the iOS Bluetooth settings. Only when I open the app again, the connection is established immediately. Nothing happens in between. Only the connect call of the CBCentralManager after the Bluetooth device is turned off. The whole thing works when the app is in the background for 3 - 5 hours. If it is over approx. 5 hours, the connection is no longer established as soon as the app is in the background.
At first I thought that the app or the BLE connection is simply killed by the system after a long time. However, the state restoration for Bluetooth is implemented and works (I tested it).
Does anyone have any idea what this could be? Are there perhaps any new settings for state restoration or Bluetooth background mode since iOS 15/16?
Many thanks in advance.
I was searching for my Bluetooth problem a few days but I did not find any useful solution. I would like reading advertising data more precisely manufacturing data from peripheral devices via ios application when it is in the background. In my case, the peripheral devices are Nordic nrf51822 chips and a central device is ios phone. I have successfully implemented the Bluetooth background mode and it works well on the ios device. The Event handler DiscoveredPeripheral is called when the new peripheral device is discovered. But the problem is that it is called only first-time the peripheral device becomes visible. If I turn off and on the peripheral device the DiscoverdPeripheral event is not called anymore. I know that this is ios restriction, but I do not know how can I handle this ios limitation. In the end, I would like that app in the background starts scanning for peripheral devices with specific UUID periodically, for example, every 10minutes. At this point, I would like to ask if this scenario is possible to implement in ios if so I appreciate for any help.
The Event handler DiscoveredPeripheral is called when the new peripheral device is discovered.
This isn't correct. It will only be called once per call to scanForPeripherals. When the device connects, you should stop scanning. When the device disconnects, which you should see as centralManager(_:didDisconnectPeripheral:error:), you can begin scanning again.
Even better, if you only want to reconnect to the same device, don't scan at all. Just call connect for that peripheral UUID. It will continue running while you're in the background and wake you up when the connect succeeds.
To push this further, implement Bluetooth State Restoration, which will allow you to automatically reconnect even after reboots.
I have a basic BLE App that I am running with Objective-C. I am using PeripheralManager and running my iPhone8 as a peripheral with serivces, characteristics added.
What I would like to do is connect to a central device that I know by Device ID or when it comes within range.
I have written a BLE App for Android that does this now. All I have to do is trigger the device.connectGatt() when onConnectionStateChange() is connected. This is in the BluetoothGattServerCallback() eventHandler.
What is the equivant for this in iOS? Keep in mind I that this is at connected state, not when the central has subscribed for services. This seems obvious in BluetoothGatt on Android but not see anything obvious in iOS PeriphalManager.
Anyone done anything similar? Seems to be a basic question, please help.
In CoreBluetooth it is the central that makes the connection.
If you know the device-specific identifier for a peripheral (ie, you have previously discovered it on this central device) then you can attempt to retrieve a CBPeripheral instance from the central and then issue a connect. This will complete when the device comes into range. If you allow background mode then this connect can be completed when your app is in the background.
I am not new to iOS, but am relatively new to CoreBluetooth and BTLE in general. Using devices running iOS 10 or later ( currently 11.2 ), I have found that if bluetooth is toggled off and on, the bonded peripheral can no longer be accessed.
After doing a bit of debugging, it seems that once bonded, the security information saved on both ends includes the address of each peer. The iOS side remembers the peripheral just fine, but after turning Bluetooth off and on again, the address of the iOS device changes itself, so to the peripheral its currently registered bonded peer (address) no longer exists. For this reason, connection between the two is no longer possible until the bonding information on the peripheral side is cleared ( Peripheral device performs direct advertisement once bonded so that only its bonded peer can see it ).
I would like to know
A) is there anyway to retain the same address on the iOS side after toggling Bluetooth off/on
B) If the address cannot be retained/recalled, what is the usual method for dealing with this sort of situation?
I have searched through the Core Bluetooth Programming reference and have googled this problem to the best of my ability, but to no avail.
Peripheral output via serial connection while bonded with the iOS central:
BTA=001EC0461948 Name=The_Lock1948 Connected=7DD350CC912D,1
Bonded=7DD350CC912D,1 Server Service=00000001 Features=20000000
TxPower=4
iOS Bluetooth off/on, then reconnect with the exact same iOS device:
BTA=001EC0461948 Name=The_Lock1948 Connected=5DDC08C0B0A3,1
Bonded=7DD350CC912D,1 Server Service=00000001 Features=24000000
TxPower=4
As you can see, the "Connected" address has changed while the peripheral remains bonded to the previous address. The only difference between the two is a toggle of the BT setting. When I say BT power off/on, I mean really turn the power off and on, not the "Allow New Connections" setting in iOS 11+.
By the way, just to add to this, I have seen 2 other BTLE peripheral devices ( keyboards ) that cannot reconnect after a iOS BT power toggle until they are reset in some fashion.
I am working with hardware that is in the process of being developed. The board uses a TI CC2541 as the bluetooth chip.
Prior to a test the board is discoverable by two devices and I am able to connect to the board and perform a test where I write and read characteristics (GATT). I perform the test again, everything goes fine until I reconnect to the device and attempt to discover its services. At that point, the board is offline and neither lightblue nor my own app can detect the device. I did a factory reset on one of the iOS devices (iPads) and it is still unable to recognize the board.
Should a factory reset remove all corebluetooth caching that has happened on the device, allowing iOS to re-cache and rediscover the board?
Can this possibly be a corebluetooth problem or a problem with my app?
Your problem seems to be related to the external peripheral. Factory reset will remove any cached data from the iOS device so as long as the peripheral behaves correctly, the rediscovery should happen as planned. This is all I can tell from the info you shared.
This issue seems to be related to hanging / adding characteristics on a peripheral during development.
I have had a similar issue and instead of clearing the cache on the iOS device, I change the Bluetooth address of the peripheral. This allows the discovery to work as expected.