78

The subject says it all, really. Documentation, insofar as it exists at all, suggests that apps written against the CoreBluetooth framework running on iOS devices can add "bluetooth-central" to their background privilege list and so process some kind of Bluetooth events whilst inactive, but which exact events do and do not get delivered?

For example:

  1. Can I carry on communications with a device I already established a pairing with?
  2. Can I issue periodic discovery requests to find devices which are out of range / I've never seen before? (For example if I wanted to be able to deliver a notification when a new interesting device is encountered)
  3. What if a device goes out of range and then comes back? Will I get disconnected and connected events without user intervention, or will I need to be foregrounded and have the user explicitly request reconnection?
Chris Smowton
  • 2,330
  • 2
  • 15
  • 14

4 Answers4

120

Nobody seemed to know, so I bought an iOS developer account and ran some experiments. Here's what I found:

When running in the foreground, you can start a scan using CBCentralManager::scanForPeripheralsWithServices. Your scan can be restricted to devices advertising a particular service, or unrestricted (pass nil for that call's parameter). It can also allow or disallow duplicates; in the former case you'll get a didDiscoverPeripheral callback every time the iPhone receives an advertisment packets; in the latter you'll only get one callback per device found.

When you enter the background, the rules appear to be as follows:

  • If you were running an unrestricted scan, it will be silently cancelled. You will not get any didDiscover callbacks.
  • If your scan was restricted (i.e. you specified one or more service UUIDs you were looking for), your scan will continue to run, but the allow duplicates flag will be ignored. This means that you will now only get didDiscoverPeripheral callbacks for new devices. If all devices were seen whilst in the foreground you will get no callbacks at all.
  • Starting and stopping the scan does not reset which devices are considered new. If there is one device present, you will only get a single callback, even across multiple scans, unless...
  • If you connect to a device, then disconnect, then scan again, the device will be enumerated again (i.e. you will get one more call to didDiscoverPeripheral). I guess iOS regards that as having "shown interest" in the device.

I don't know whether connect attempts to nonconnectable devices (e.g. BLE Advertisers, like those implementing the proximity profile) is good enough as my example devices are connectable. However at least for connectable devices, this scan/connect/disconnect/scan procedure suffices to poll for a device's presence in the background.

The above results were gathered using an iPhone 4S running iOS 5.0.1

Chris Smowton
  • 2,330
  • 2
  • 15
  • 14
  • 2
    Hey Chris. Interesting! I don't understand one thing though. Can the process keep running in the background if it is communicating with a Bluetooth design? (For example, Could I connect a heart rate monitor and then move the application to the background and expect it to keep running?) – Ben Jun 07 '12 at 09:17
  • 2
    Hi Ben. It won't keep running like it does in the foreground, but it will continue to be executed when Bluetooth events of the kind I'm describing above occur. A problem I've encountered is that even in this situation, when there's no user interaction for a while the phone will go to sleep and the app will stop being invoked. I've worked around this by registering (falsely) as an audio application, which prevents suspension; this is obviously inadmissable for the app store however. – Chris Smowton Jun 19 '12 at 14:11
  • Hi Chris. Great post. Your last comment negates the statement in this post: http://lists.apple.com/archives/bluetooth-dev/2011/Dec/msg00007.html This is not good news. Do you think this is an actual error in the implementation? Have you set up a connection to a device? Can you confirm that value update notifications stop as well? Thanks. – allprog Aug 08 '12 at 21:40
  • One more comment. This post is probably related to your observation: http://stackoverflow.com/questions/10140260/background-time-issue-for-bluetooth-le-app-for-iphone-4s Let's keep these in sync if possible. – allprog Aug 08 '12 at 21:44
  • Hi, i have observed that the didDisconnectPeripheral: method gets called even in the background mode. However and NSFileManager operations or Networking operations do not get executed. Could you explain exactly what kind of code is available for execution here. If no code can be executed here then what would be the point of calling this delegate in background? – NSRover Jan 09 '13 at 10:49
  • Sorry, I have no idea -- I no longer have access to a dev iPhone so I can't help you further. – Chris Smowton Jan 09 '13 at 15:29
  • @ChrisSmowton, could you tell about RSSI monitoring? is it available in background after restoration? – gaussblurinc Jun 30 '15 at 13:00
  • Sorry, same answer as above :) – Chris Smowton Jun 30 '15 at 14:04
  • 1
    @ChrisSmowton I know you don't have an iOS device anymore. But do you have an idea as how one would differentiate between iOS ignoring a duplicate and iOS not finding a peripheral? – shreyashirday Jul 28 '15 at 15:53
  • 3
    If you haven't seen it since you last connected to it, it's not there. If you have seen it, the only way I know to discover it again *when in the background* is to attempt a connection. – Chris Smowton Jul 28 '15 at 20:37
  • If I keep the peripheral connected and scan for it again(even though its connected), will it get discovered in didDiscoverPeripheral delegate method? – Ameet Dhas Apr 07 '16 at 06:48
  • @Bhushan: No, connected devices won't be "discovered", hence no call to `didDiscoverPeripheral`. They're only discovered if not already connected. – Lars Blumberg Oct 10 '16 at 17:49
  • @ChrisSmowton does the centralManagerDidUpdateState method gets called when user turns on the bluetooth after a couple of hours? I am stuck where centralManagerDidUpdateState doesn't get called if I turn the radio off and turn it on after a few hours. – Saleh Jan 03 '18 at 16:26
  • @Saleh sorry, don't have the hardware any longer. – Chris Smowton Jan 03 '18 at 20:54
9

In addition to Chris's answer:

  • If your app has "bluetooth-central" background mode and is connected to a peripheral, you can receive notifications (peripheral:didUpdateValueForCharacteristic:error:) from the peripheral in background, even after 10minutes.

So when you want to continuously run in background you have 2 options:

  • Run the "connect, disconnect, scan again" loop
  • Make the peripheral send notifications

Later should be the "Event backgrounding" from WWDC 2012 Core Bluetooth videos https://developer.apple.com/videos/wwdc/2012/ But the former looks like a hack, I don't want to rely on it.

I tested this on iPhone5, iOS6.1.4


Apple finally released the Core Bluetooth Programming Guide and here's the official note about

Core Bluetooth Background Processing for iOS Apps

mash
  • 3,416
  • 2
  • 27
  • 33
7

It is also good to note the behavior of backgrounding and CoreBluetooth related to the iBeacons, although Apple likes to think of this as a CoreLocation functionality:

  1. When notifications for an iBeacon region are turned on, they will notify the user of region entry or exit. These notifications can be made to depend on whether the display is on or off. These notifications will work even when the app requesting notifications is in the background. (This much is clear in the documentation).

  2. Not so obvious: If you use the iBeacon ranging API, then your app has to be in the foreground. It does not explicitly say this in the documentation-- in fact, one can be mislead to think that ranging should work in the background from the documentation. However, an Apple engineer clarifies this in a post buried somewhere in a long thread on the Apple developer forum, and I've seen this fail too. Ranging will work only in the foreground.

  3. One can discover other services being advertised by a peripheral advertising iBeacons. But this will work only in the foreground. So if you want the central to be notified of proximity using iBeacons, and then do some other transactions using other BLE-based services, this will work, but only in the foreground. It will not work in the background. For transactions with BLE-based services in the background, the advertisement has to be a regular BLE advertisement, not an iBeacon. You cannot use an iBeacon advertisement to help the discovery process in the background, and then switch to using BLE-services in the background. (I would have very much liked this to work, but no dice).

user108
  • 121
  • 2
  • 5
4

I've just learnt background mode for BLE devices on iOS8.3 & 8.4 and have found some differences from above:

  1. if I start

    [centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:kServiceUUID]] options:@{CBCentralManagerScanOptionAllowDuplicatesKey : @YES }];

from

- (void)applicationDidEnterBackground:(UIApplication *)application

I found enumeration returns the same device every call with different RSSI, so CBCentralManagerScanOptionAllowDuplicatesKey isn't ignored.

  1. If app is in foreground it discovered BLE device 50 times in sec. If app is in background but the phone screen is active app discovered BLE devices 6times in sec. If phone screen is blocked app discovered BLE devices 1time in sec.