14

What I want is for my iOS device to be advertising a Bluetooth LE service all the time, even when the app isn't running, so that I can have another iOS device scan for it and find it. I have followed Apple's backgrounding instructions here:

https://developer.apple.com/library/ios/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/PerformingCommonPeripheralRoleTasks/PerformingCommonPeripheralRoleTasks.html#//apple_ref/doc/uid/TP40013257-CH4-SW1.

I can get it to advertise in the foreground ok and sometimes in the background but it doesn't stay advertising all the time. If you have it setup to run in the background, shouldn't it start advertising even after a device restart, just like background location services automatically start working after a restart? Are their limitations to the backgrounding that are not listed (or hard to find) in Apple's docs? Does anyone have an example of a Core Bluetooth Peripheral advertising correctly in the background?

Thanks...

jpcoder
  • 1,125
  • 2
  • 9
  • 15
  • You need to implement restoration for the peripheral manager. Watch the WWDC video to see how it needs to be done. However, keep in mind that there is a bug that crashes the app when the manager is restored if it had any peripherals connected. – allprog Oct 07 '13 at 22:50
  • I watched the video. It was for a central and not peripheral. Does anyone have a working example of a background peripheral? Also, about this bug, does that have affect a peripheral? – jpcoder Oct 08 '13 at 03:54
  • It's the same scheme for both managers. The bug affects the peripheral. – allprog Oct 08 '13 at 07:26
  • So is backgrounding basically useless until they fix that bug? Or is there a workaround? Of course, the problem I was talking about seems like it would be unrelated to this bug. My problem was with it not advertising. In the background, this should be done by the OS without my app even running and before the manager is restored. – jpcoder Oct 08 '13 at 12:08
  • 1
    You need to make sure that the centrals disconnect before the app is terminated and this has to be done in a proprietary way, there is no API for it. That's all to this bug. I'll post an answer for the background advertisement. – allprog Oct 08 '13 at 12:22
  • Apple confirm here that state restoration across reboot is not supported http://lists.apple.com/archives/bluetooth-dev/2014/Apr/msg00047.html – collinsrj Apr 28 '14 at 16:09

2 Answers2

9

Background advertisement is possible if you add the bluetooth-peripheral backgrounding mode to the app's plist. Once you do that, your app will continue to receive the callbacks even if backgrounded.

The advertisement is a tricky beast as Apple implemented several optimizations to reduce the power consumption and these reduce the quality of the advertisement as soon as the app is backgrounded. Namely: the rate is reduced severely, the advertised services are not included and the local name is not included either. Once the app comes back to foreground, these restrictions are invalidated.

In the general case, this kind of backgrounded operation requires the app to be running. With iOS 7 the restoration process has been implemented that allows the OS to act on the app's behalf while it is terminated and restore the app when some transmission or other operation is imminent. This requires you to add the restoration key to the initialization options of the CBPeripheralManager/CBCentralManager. Starting your application once is still required but after that, iOS will continue to act as the BLE facade towards the centrals/peripherals.

UPDATE: I ran a loop on the Apple bluetooth-dev list as well with this question and found that Core Bluetooth managers were declared to be not able to restore after reboot. This is not described in any documentation but probably was mentioned in the WWDC videos. We should file a bug and replicate it to raise Apple's awareness.

allprog
  • 16,540
  • 9
  • 56
  • 97
  • I have done all that you say here but I have not seen it advertise after a reboot. Without it working after a reboot I don't see the backgrounding/state restoration all that useful. Do you know where you have seen these reports of advertising after a reboot? – jpcoder Oct 08 '13 at 16:31
  • I searched through the apple bluetooth list archives and the ADF Core Bluetooth section but couldn't find this message. I don't remember where I've seen it. I just ran a test and couldn't get the restoration triggered after reboot and advertisement didn't start either. – allprog Oct 08 '13 at 20:06
  • Bummer. :) Thanks for trying though. Maybe it just doesn't work that way. Maybe they did that for power saving but it does make this a lot less useful if it can't restart after a reboot. Do you know if CBCentralManager scanning works the same way? If you couldn't continue scanning in the background after a reboot that would be rather limiting as well. – jpcoder Oct 08 '13 at 20:29
  • I haven't tried the central case but why would it differ? Generally, iOS does not allow any app to start automatically or do anything on its own. Maybe voip is an exception but I don't have experience with that. I know, this is not an authoritive answer but that's all I have now. :) – allprog Oct 10 '13 at 07:17
  • I'm pretty sure location services can start after reboot. Lets say you had a bluetooth le door lock (peripheral) and you wanted to use your phone (central) to unlock the door when you got fairly close to it. If corebluetooth would scan in the background all the time then you could do this. But if it stops scanning after a reboot (and seems to also if the app is forcibly killed) then you would be stuck outside your house until you started the app which makes it not quite as useful. – jpcoder Oct 11 '13 at 19:51
  • @jpcoder Ah, ok, I remember. The guy I mentioned originally talked about iBeacon ranging. Yes, that is restored after reboot. I'm currently investigating this issue in more detail. – allprog Oct 13 '13 at 06:17
  • @jpcoder I found the ugly truth. Updated the post accordingly. – allprog Oct 14 '13 at 08:10
  • Thanks for the info. At least I now know the limitations. Do you know which WWDC video that is in and where it was mentioned? I didn't catch this in the '13 Core Bluetooth video. – jpcoder Oct 14 '13 at 12:16
  • I watched the videos once again but probably missed this point will try again. :) – allprog Oct 15 '13 at 19:39
  • Would you happen to know whether this also applies to the advertising of `CLBeaconRegion` peripheral data? – Yazid Apr 03 '14 at 23:12
  • I don't know exactly but I'm pretty sure that you'll get the answer if you ask this in a question. – allprog Apr 04 '14 at 19:20
0

The implementation can be founded here: https://developer.apple.com/library/content/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/PerformingCommonPeripheralRoleTasks/PerformingCommonPeripheralRoleTasks.html#//apple_ref/doc/uid/TP40013257-CH4-SW5

Its very simply actually.

<CBPeripheralManagerDelegate>

@property (strong, nonatomic) CBPeripheralManager *peripheralManager;

...

- (NSDictionary*) advertiseNotBeacon {
    CBUUID *myCustomServiceUUID = [CBUUID UUIDWithString:@"MY_UUID"];

    CBMutableCharacteristic *myCharacteristic = [[CBMutableCharacteristic alloc] initWithType:myCustomServiceUUID
                                                                                   properties:CBCharacteristicPropertyRead | CBCharacteristicPropertyNotify
                                                                                        value:nil permissions:CBAttributePermissionsReadable];

    CBMutableService *myService = [[CBMutableService alloc] initWithType:myCustomServiceUUID primary:YES];
    myService.characteristics = @[myCharacteristic];

    self.peripheralManager.delegate = self;
    [self.peripheralManager addService:myService];

    return @{CBAdvertisementDataServiceUUIDsKey : @[myService.UUID],
             CBAdvertisementDataLocalNameKey: @"MY_NAME"
             };
}

...

[self.peripheralManager startAdvertising:[self advertiseNotBeacon]];

Doing this, you will start advertising a peripheral service.

Now, if you want to keep the service running in background, read the documentation in this link: https://developer.apple.com/library/content/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothBackgroundProcessingForIOSApps/PerformingTasksWhileYourAppIsInTheBackground.html#//apple_ref/doc/uid/TP40013257-CH7-SW1

Quick steps: Open info.plist Add a new par key/value

Required background modes
      App shares data using CoreBluetooth

Apple says to ctrl + click on any key/value and add a add the following, but exactly the same as explained before.

UIBackgroundModes
      bluetooth-peripheral 

Dont forgot about the limitations of running the service in background:

  • The CBCentralManagerScanOptionAllowDuplicatesKey scan option key is ignored, and multiple discoveries of an advertising peripheral are coalesced into a single discovery event. If all apps that are scanning for peripherals are in the background, the interval at which your central device scans for advertising packets increases. As a result, it may take longer to discover an advertising peripheral.
  • These changes help minimize radio usage and improve the battery life on your iOS device.
Pedro Romão
  • 2,285
  • 28
  • 22