0

Setup, uniqueness of the situation, and success scanning in foreground

I am trying to pick up bluetooth readings from a CBPeripheral device. What is interesting about this particular device is that it sends out UUIDs that are embedding information in them directly. (This seems strange, but I don't know enough about BLE to know whether or not that's typical. There is no actual connection occurring in the end - only advertisements are being sent out.)

In the foreground, I am able to identify which readings are mine because [peripheral name] remains constant. So I'm able to pick up the readings that are relevant by doing the following check inside of didDiscoverPeripheral:

if ([[peripheral name] isEqualToString:@"UNIQUE_IDENTIFIER"]) {
    NSLog(@"*** Got a reading ***");
}

This is working nicely in the foreground - I am running

[self.centralManager scanForPeripheralsWithServices:nil options:nil];

in a loop (details there seem irrelevant) and the code is able to print out all of the readings that I expect it to print.

Trouble scanning in background and attempts to solve

My app's Info.plist contains the following entry:

I have also check the (what I think is) the appropriate field in the Capabilities tab in XCode:

Neither of these things have turned out to be useful. didDiscoverPeripheral is called perfectly up until the point where I close my application, at which point it stops immediately.

One other thing that I read on the internet was that background processing still won't happen when scanForPeripheralsWithServices is called with nil, however if a non-empty array of services is passed instead, then it should succeed. I'm not sure if this is correct. The problem is, I have only been able to find examples of calling scanForPeripheralsWithServices where the services are identified by their UUIDs, for example

NSArray *services = @[[CBUUID UUIDWithString: @"2456f1b9-26e2-8f83-e744-f34f01e9d701"]];
[self.centralManager scanForPeripheralsWithServices:services options:nil];

but not their name property.

The question

So I guess my question, after all of this, would be: Would providing an array of name filters (instead of UUIDs) help the application to run in the background, and if so, how would I write that in code? If not, what am I missing such that my app still only works in the foreground?

EDIT: I had previously used the terminology "identifier" when I think I meant to say "name", so I went back and changed those. From the documentation, here is the name value that I would like to scan for in the background https://developer.apple.com/documentation/corebluetooth/cbperipheral/1519029-name?language=objc

wheresmycookie
  • 683
  • 3
  • 16
  • 39
  • you app will not scan for new devices in background but (briefly) can keep connected to already connected devices and monitoring them _(source: [Apple](https://developer.apple.com/library/content/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/CoreBluetoothBackgroundProcessingForIOSApps/PerformingTasksWhileYourAppIsInTheBackground.html))_. – holex Feb 13 '18 at 11:32
  • @holex the rest of that sentence says that this pertains to "apps that have not declared to support either of the Core Bluetooth background execution modes". But *I think* I've done that properly in my app. – wheresmycookie Feb 13 '18 at 11:36
  • and it also says _"`bluetooth-central` – The app uses the CoreBluetooth framework to __communicate__ with a Bluetooth accessory while in the background."_, I emphasised the keyword here: "communicate" (=interact) and not "scan". – holex Feb 13 '18 at 11:42
  • @holex another quote from the background mode section: "While your app is in the background you can still discover and connect to peripherals, ..." So it seems as if you can discover devices as well while running in the background. – wheresmycookie Feb 13 '18 at 11:45
  • And actually the remainder of that same paragraph makes it clear that scanning in the background, although it may behave differently in some ways, is a real feature. (@holex) – wheresmycookie Feb 13 '18 at 11:48
  • ...and that the second part of the sentence is: _"(...) the system __wakes up__ your app when (...)"_ not "lets your app running wild in background". – holex Feb 13 '18 at 11:52
  • @holex thanks but this conversation isn't useful anymore. You said that "you app will not scan for new devices in background" but now I guess it can? As per my question, **waking up** would actually be useful for what I'm trying to achieve. But I'm looking for people who understand bluetooth on iOS and can help me identify why this currently isn't happening. – wheresmycookie Feb 13 '18 at 11:59
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/165045/discussion-between-wheresmycookie-and-holex). – wheresmycookie Feb 13 '18 at 12:01

1 Answers1

1

In order to scan for new devices in the background you must specify the UUIDs of the service(s) that you are interested in. The documentation is quite clear on this.

The identifier for a device is a value locally determined by iOS, not the device itself and will vary for different iOS devices connecting to the same peripheral. If you know the identifier for a device that you have previously discovered then you can use the identifier to connect to the device but you can’t scan for an identifier.

It is possible for a peripheral to include data in its service advertisement and perhaps this is what your peripheral is doing. If so, then you will not be able to get readings in the background since duplicate device discovery events are not delivered when your app is in the background.

You can discover and connect to a new device in the background as long as you know the service that it is advertising but any subsequent data transfers will require the device to issue a notify on a changed characteristic. It cannot use the manufacturer data portion of the advertising frame.

Paulw11
  • 108,386
  • 14
  • 159
  • 186
  • Thanks, this is insightful. I've been looking for ways to scan using a regular expression or wildcard UUID, but so far haven't been able to find anything. – wheresmycookie Feb 15 '18 at 12:24
  • Actually Paulw11, I think I mispoke in the question originally (edited now). I'm actually trying to filter by the name property (link provided in EDIT). Do you happen to know if this is possible? Haven't seen anything of that nature yet. – wheresmycookie Feb 15 '18 at 12:31
  • No, you can't. You can only search for the service(s) that are being advertised. To filter by name you would need to have your code check the name of the newly discovered device and you won't be able to do that in the background without specifying a service to scan for. – Paulw11 Feb 15 '18 at 15:11
  • Thanks - am doing a little more research here, and if it confirms all of this I'll come back and choose this answer. Thanks! – wheresmycookie Feb 15 '18 at 15:54