I currently have an app that connects to a BLE device and is able to exchange packet data, send messages to other nearby BLE devices, notify when connects/disconnects happen. The problem is when the phone gets locked and the app gets suspended/put to sleep by the system. When it is a short duration, the app gets woken up and notifies of new messages. But when a few hours have passed the device gets disconnected completely. The whole point of the app is to receive these messages regardless if the phone has been locked for like 2-4+ hours (edge case). I don't know the exact time it gets disconnected.... I am only able to conduct a test of a couple hours, or after I wake up from a night's sleep and I can't simulate this on XCode.
This app is using open source stuff, and a similar but different app is able to keep a BLE connection for way longer. This other app uses location updates permissions and mine does not. Some users have said that their background connection is reliable even if they have location set to while using app only. I ran a test and this app stays connected for longer while mine does not, even if no gps/location/or message notifications updates happen.
Can I achieve the same connection reliability without using location updates permission? What if I implement 'background refresh' of some sort or 'acts as bluetooth LE accessory'? If my app receives at least 1 notification every hour will that prevent this? I read up on Apple's "Adding Support for State Preservation and Restoration" docs, it's not well documented but do I do that? What option would you suggest?
Core Bluetooth provides very good support for long-term background operations. It handles both the case where the app is stopped by iOS while suspended (due to memory or other resource pressure) and where the device itself disconnects for some reason (out of range, power loss etc).
To enable this to work you need to ensure you have opted in to Core Bluetooth state restoration. This is described in this Apple document - Even though it is an old document, it is still valid.
The general strategy is:
CBCentralManager
, give it an identifier via CBCentralManagerOptionRestoreIdentifierKey
didDisconnect
delegate method, immediately call connect
on the peripheral.didConnect
delegate method and you process as usualCBCentralManager
with the same restoration identifier, you will get a call to the didConnect
delegate method and you process as usual