I am currently using CoreBluetooth to scan for peripherals. Every 30 seconds it sends its packet of information to the cloud by using a Timer. This is working good in foreground. I would like this exact operation to function seamlessly in the background too.

I have declared a CBUUID ahead of time for it seek out the designated peripheral in the background. Upon entering background mode, the scan stops functioning after 10~ seconds. How do I continually make the scan operate continue in the background?

I was looking into Bluetooth State Preservation, would this alleviate the issue? Should it also not be on the main thread?

After the packets are advertised I would like them stored in memory. I am aware the DiscoverPeripherals logs the peripherals... is it possible to log the RSSI and additional peripheral data in chronological order and have it an operation take affect per an interval? I was looking at BGProcessingTask to fire off a function in the background. Would a better approach be to use CoreData to store the memory and clear it after? Best/easy suggestion is appreicated.

I have changed the CBUUID to the right peripheral for centralManager.scanForPeripherals(withServices: [uuid], options: nil) with uuid being the CBUUID. That seem to be allowing the peripheral to be detected in the background. It stopped logging the scan after a short period of time. Right when I put the app in background, it functions properly for a bit. I theorize it could just be calling it on the same thread and it may not be operating in the background all together. I did test this by changing the the withServices to nil, the result was that the operating was not being logged at all once I closed to the background.

I was expecting the operation to continually be scanning on the basis of the Timer every period, after the period is up it would send it the cloud just how it was doing it in the foreground.

1

There are 1 best solutions below

9
On

There are lots of restrictions on iOS apps when they are not in the foreground. Once an app moves from the foreground it is suspended and can only execute in the background for specific reasons and for limited durations.

In general, anything based on a Timer will not fire when the app is not in the foreground.

Some Core Bluetooth events are delivered while your app is in the background:

  • Pending connect operations can complete with a corresponding delivery to your app.
  • Peripheral disconnections will be delivered to your app
  • GATT Notify/Indicate operations from a connected peripheral will be delivered to your app.
  • Discovery of new peripherals advertising a service that you are specifically scanning for will be delivered to your app.

It is this last behaviour that you are relying on.

While you have done the right thing by specifying the specific service you are interested in, your plans are being thwarted by the fact that Core Bluetooth will not deliver repeated discovery notifications for a particular peripheral.

When your app is in the foreground you can use the CBCentralManagerAllowDuplicatesKey option to request a discovery notification each time a peripheral advertisement is seen, even if an advertisement from that peripheral has been seen before. This option has no effect when your app is not in the background.

The best way to gather data on a periodic basis from a peripheral (whether in the background or foreground) is for that peripheral to send its data via Notify/Indicate, however you seem to be trying to scan for the existence of peripherals rather than gather specific data from them, so this may not work for you.

When one of the supported Core Bluetooth background events occurs and your app has been jettisoned, State restoration allows your app to respond after iOS relaunches your app. It will not help you in this case.

It probably isn't possible to do what you want, at least not without changing the behaviour of your peripheral.