Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS CoreBluetooth: State Preservation and Restoration

hope to get some input here.

In my current iOS project I am using CoreBluetooth with swift. The app is enabled to communicate using CoreBluetooth in the background which basically works, kind of. The peripheral requires to have an active connection with the iOS device in order to work as expected. Whenever the connection breaks, the peripheral stops it current action. This also happens when the app is closed due to memory pressure. In that case the peripheral should not stop working, so there's a problem. In order to solve it, I followed apples core bluetooth programming guide to implement the state preservation and restoration background mode which basically says:

  1. Initialize the CentralManager with a restoration identifier. Delegate = self.
  2. Implement the willRestoreState delegate method. NSLog something
  3. Check launchOptions for a special key. NSLog something.

I force iOS to close the app while it is in background using this common project: BackgroundKill. Of course the app is not running in debug mode anymore, that's why I added some NSLog statements at important points to look for in the device console. The good news: the connection is not cancelled anymore when the app is terminated, iOS is now acting as expected to keep the connection so the peripheral won't stop working. Strike! There's no communication between central and peripheral during this time except for the battery service which the app is subscribed to. The only reason to have an active connection is to prevent the peripheral from stop working.

When relaunching the app manually now, none of the mentioned NSLogs shows up. The willRestoreState delegate is never called and the launchOptions are nil. I tried to use the queue "DISPATCH_QUEUE_CONCURRENT" instead of nil when instantiating the CentralManager. With no effect.

How am I supposed to use the preserved connection when relaunching the app? Why is the willRestoreState delegate never called? Am I missing something here? Is it mandatory to receive data while being backgrounded/force closed by system in order to use the state preservation and restoration?

Thanks for helping. :)

like image 860
STEX Avatar asked Jan 06 '15 11:01

STEX


1 Answers

Finally made some tests and got results. It turns out that the app is launched into background when needed, which means whenever the peripheral sends data on the preserved connection. iOS launches the app through didFinishLaunchingWithOptions in this case, so you have ~10 seconds to check your launch options and do something. So my problem was related to the fact that there was no data sent on the connection, seems we now have to change the firmware of our peripheral to sort this out.

The delegate willRestoreState is called when relaunching the app manually. At this point iOS provides not only the recently used central but also a list of connected peripherals and even the recently subscribed services. So I just had to restore my objects and get the subscribed characteristic from the right service of the connected peripheral to be fully functional again.

like image 59
STEX Avatar answered Sep 27 '22 22:09

STEX