0

I'm developing an App that needs, in certan scenarios, to be connected to a bluetooth Peripheral indefinitely.

Before I go on with my question, I want to confirm that:

  • I'm initializing my CBCoreBluetoothManager in didFinishLaunchingWithOptions:.
  • I have bluetooth-central background capabilities enabled.
  • I am using State Preservation and Restoration by having the Manager being initialized with a key, and implementing willRestoreState:
  • Before my problem happens, I have a successful connection with my Peripheral, I get its service (I'm only looking for one) and its characteristic (again I'm only looking for one) for which I do set setNotifyValue: to YES. Aditionally, while both in the Foreground, and the background, I get callbacks on didUpdateValueForCharacteristic: everytime the characteristic's value updates.
  • I am simulating the "suspended state" with kill(getpid(), SIGKILL) (I have also tested it by just putting the app in the background, and letting it sit for 1 hour+)
  • When I say suspended, I mean the actual Suspended state. Which I believe every app eventually gets there, after being put in the background for an amount of time.

The problem that I am having, is with getting callbacks on didUpdateValueForCharacteristic: when the app is suspended. Again I do get callbacks if the app is in the background, but not when it is suspended. Meaning, the app does not get woken up by a value update on the characteristic.

The funny thing is that while I have the app in suspended mode, and I walk out of the Peripheral range to disconnect, and then back in range to re-connect, the app will be woken up, because it will try to restore (it calls willRestoreState:) and for a brief time, will listen to any characteristic values updates.

To sum up, while my app is in the suspended state, and in range of the Peripheral, didUpdateValueForCharacteristic does not get called, meaning the app does not get woken up, by what I am 100% sure, is a characteristic value update. It would however, wake up the app, if I walk out of the Peripheral's range, and back in, because I am supporting State Preservation and Restoration.

From Apple's documentation:

The system wakes up your app when any of the CBCentralManagerDelegate or CBPeripheralDelegate delegate methods are invoked, allowing your app to handle important central role events, such as when a connection is established or torn down, when a peripheral sends updated characteristic values, and when a central manager’s state changes.

It seems that I should be getting those updates, has anybody ever had a problem like this?

Any help is appreciated!

Thanks in advance

  • You aren't simulating the suspended state; you are simulating the terminated state. The suspended state is when the app is still in memory but not actually executing in the background; so if your app is running and you press the home key, it will move to the background state (briefly) before moving to the suspended state. When something happens, such as a characteristic update, then your app moves from the suspended state to the background state to process the update - this is working. Depending on how an app enters the terminated state, iOS may not relaunch it. – Paulw11 Sep 26 '17 at 23:55
  • That said, you seem to indicate that iOS is relaunching your app from the terminated state when the peripheral goes out of range and then comes back, so what you are doing should work for characteristic updates too. You can monitor the device log via the devices window in Xcode to see what iOS is doing in relation to detected Bluetooth events and when it decides to relaunch your app. – Paulw11 Sep 26 '17 at 23:57
  • I have confirmed your findings with a test app of my own; Peripheral discovery will relaunch the app but an update to a connected peripheral's characteristic does not. This is either a bug or Apple's documentation is incorrect; You may need to raise a case with Apple – Paulw11 Sep 27 '17 at 00:22
  • @Paulw11 thank you very much for taking a look. I think you may be right about `kill(getpid(), SIGKILL)` terminating instead of suspending, it's odd however, that it doesn't call `applicationWillTerminate:` which is what made me thinkg it was suspending it. In any case, I still wanted the app to be woken up by the OS when an update happened, whether from suspension or termination by the system. Given your findings, and mine, I'm starting to think this is indeed a bug, or as you pointed out, an incorrect documentation. I'll keep looking into this and post any intersting findings here. – Carlos Conejo Sep 27 '17 at 14:38
  • `applicationWillTerminate` is called when iOS is going to terminate your app, but it is not called if you kill the app with SIGKILL or if you swipe up or terminate the app from Xcode debugging. However in all of these cases iOS relaunches my app when the peripheral is rediscovered. I also found that as long as I stayed in range if the peripheral, iOS did not terminate my app that was receiving notifications; this was over a period of an hour or so and I did other things on the device. – Paulw11 Sep 27 '17 at 19:46
  • This is proper way to trigger restoration state. It work on iOS 10, it does not always (toggling bt off/on helps sometimes as well) work on iOS 11 I confirm. – b.zdybowicz Oct 09 '17 at 12:42
  • @Paulw11 Does the app gets relaunched in the background if the central's state changes? Say if the central is connected to a device and user turns off the bluetooth and turns it back on after the app is suspended, will the app be woken up and CBManagerStatePoweredOn be called? – Saleh Jan 04 '18 at 19:58

0 Answers0