I have a question regarding state Preservation and Restoration for Core Bluetooth on iOS 7.
I can't seem to get it to work properly. I have followed every guidline that apple mentions in their documentation for core bluetooth as well as the general documentation for state preservation.
For example here: Core Bluetooth Background Processing for iOS Apps and here: iOS State Preservation and Restoration
I can get the general state preservation to work on the device (for view controllers and objects etc.), but not for the bluetooth manager.
As far as I know the cheklist look like this:
Opt in preservation and restoration when you allocate and initialize a central manager object by assigning a restoration identifier in the options dictionary for the key CBCentralManagerOptionRestoreIdentifierKey.
Reinstantiate any central manager objects after your app is relaunched by the system. This is done in app delegate when the application:didFinishLaunchingWithOptions: is called. Here I am supposed to look for the UIApplicationLaunchOptionsBluetoothCentralsKey in the options dictionary and then reinstatiate the CBManager with that key. It is here where things go wrong since there are never any identifiers for that key, and thus I can not reinstatitate it.
Implement the appropriate restoration delegate method. I have done this step also, but since the manager is never re-instantiated I never receive this delegate callback.
The app is working fine in the background and I have followed all the steps for that part as well.
Now, having said all this, I am not entierly sure how to test this and that might be a part of the broblem. The way I do it now is to press the home button on the iOS device (actuall device) so that it puts the app into background and goes back to the home screen. While doing this I can tell that all the regular state preservation calls are acheived by looking at my log output. After this i quit the app by pressing the stop button in Xcode to kill the background process. I now restart the app through Xcode and once again I can now see all the regular state preservation code being executed and the state gets restored on everything except the bluetooth manager.
If this is wrong, then please let me know. But in all, I am very confused about this since it says in the Core Bluetooth docs that the preservation occurs only when "your app is relaunched by the system". What does that really mean? I also read a post on the Apple developer forum that since iOS 7 the OS will now never relaunch the app for any reason if the user kills the app manually which I am doing..
Any help regarding this would be much appreciated!
/A
When you click home button to send app to background, it it suspended, and can handle Bluetooth delegates and run in background for 10s, this feature could be realize by " add bluetooth central in background mode in info.plist", and do not use State Preservation & Restoration.
If your app is terminated by IOS, due to memory pressure, it can't handle bluetooth delegates anymore. In this case, if you used State Preservation & Restoration, your app can be relaunched to background to run again, also for only 10s. After 10s, it would move to suspended state. Only in this situation, CBCentralManager's willRestoreState can be triggered.
You can add code
[kill(getpid(), SIGKILL);]
to a button action, when you click the button, your app will be terminated by IOS just like killed by memory pressure, and then "willRestoreState" will be triggered.
Good luck.
First, note that state preservation of view controllers has nothing to do with restoration of Core Bluetooth managers.
Important: Restoration doesn't work for scanning, static characteristics and generally any use cases that do not generate connection related events.
Now the steps:
Depending on what you want to test, consider the applicable points in the list. Use logging in your tested app and watch the logs in the organizer to see what happens over time.
I was able to get this working with scanning in the background (along with connecting and transmitting data). There are important difference between how your app was terminated and if iOS will preserve and restore your Core Bluetooth Manager.
Adding "App communicates using CoreBluetooth" to "Required background modes" in Info.plist covers most situations. Your central manager will continue to work in the background — either when the user presses the home button or locks the phone (or both). However you will never get the "willRestoreState" delegate call in these scenarios as your central manager is still being handled by your application (it's still in memory).
Preservation and restoration only comes into effect in one scenario — your app was terminated by iOS due to memory constraints. The easiest way to force this for testing it to load 3-4 memory intensive games while your app is in the background. If you review the device console, you're waiting for this message:
"Apr 4 13:16:47 Michaels-iPhone SpringBoard[58] <Warning>: Application 'UIKitApplication:com.oculeve.TearBud[0x6df4]' was killed by jetsam.”
iOS will take over you central manager at this point. If it was scanning, it will continue scanning, if it was connect to a peripheral, it will continue to be connected. In the event that you receive a central manager delegate call (didDiscoverPeripheral, didUpdateValueForCharacteristic) iOS will launch your application again in the background. At this point you will get the willRestoreState delegate call. At this point your app is back in memory and will work as describe above. Note that you need may need to do some restoration in willRestoreState if you were connected to a device. This is all covered in the WWDC 2013 Core Bluetooth video demo.
The kicker seems to be that restoration/preservation does not work if you manually close the app from the system tray (swiping up on your app). I'm assuming Apple's reasoning for that is in this case the user is explicitly closing the app and all Bluetooth communication should cease. This is also true is the user restarts their phone. I'm assuming this is because a restart is basically equal to swiping up to close all the apps in the system tray. If you get to this point, you can only reconnect once the user opens your application again.
Something to point out is that just because your app is in the system tray doesn't mean it's in memory.
Why Apple doesn't just tell you this in the documentation is beyond me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With