8

I am attempting to have my app scan for BLE devices in the background and to search for a bit of advertisement data in Swift. I've been unable to find any tutorials or questions on here that cover this.

Basically, is there a way of doing this automatically in the background when the app isn't in the foreground and when the user has restarted their phone?: Obtaining Bluetooth LE scan response data with iOS

I hope you can point me in the right direction. Thank you

Community
  • 1
  • 1
user3246092
  • 880
  • 2
  • 13
  • 28
  • I'm almost positive this is forbidden in iOS. So, no. I don't believe this is possible. In all likely-hood, you probably would want to use something like Bluetooth classic. However, not just anyone can use Bluetooth classic with iOS. You have to be apart of Apple's MFI program and get special permission from Apple themselves. – Oxcug Jul 25 '15 at 22:39
  • 1
    As long as the device is advertising a BLE GATT service then scanning for services in the background is covered in Apple's Core Bluetooth Programming Guide. Have you read that? Have you tried anything based on that ? – Paulw11 Jul 25 '15 at 22:41
  • Affirmative, what I've read pertains to identifying devices based on UUID and identifier. I'm attempting to do it via advertising data without actually connecting to the peripheral presumably requiring a background scan for advertising data. – user3246092 Jul 25 '15 at 22:45

1 Answers1

11

Step 1: Enable bluetooth background mode for your projects capabilities

enter image description here

Step 2: Make sure the appropriate stuff was added to your info.plist file

enter image description here

Here is the plist code if it didn't add it:

<key>UIBackgroundModes</key>
 <array>
  <string>audio</string>
  <string>bluetooth-central</string>
 </array>

Then, when you call "scanForPeripheralsWithServices" on your CBCentralmanager you have to specify an array of services to scan for. You can't pass it an empty array. It will still scan if you pass nil, just not in the background.

So specify an array of service UUID's like this:

let arrayOfServices: [CBUUID] = [CBUUID(string: "8888")]
self.myBluetoothManager?.scanForPeripheralsWithServices(arrayOfServices, options: nil)

Now if you care about options you can pass a dictionary of options in place of the nil I passed above. Mostly, this is used to specify if you want to continuously see a devices RSSI before you connect or if you just want the advertisement packet once. Put a:

println(advertisementData["kCBAdvDataLocalName"] as! String) 
println(advertisementData["kCBAdvDataManufacturerData"] as! NSData)

in the "didDiscoverPeripheral" delegate method to observe the different behavior.

Here is the Dictionary you will pass if you want duplicate keys:

let dictionaryOfOptions = [CBCentralManagerScanOptionAllowDuplicatesKey : true]
self.myBluetoothManager?.scanForPeripheralsWithServices(arrayOfServices, options: dictionaryOfOptions)

Now Apple says that when your app goes in the background mode it defaults this scan option to false but as of iOS 8.3 I have see it keep scanning with duplicate keys.

One final note on background execution. If the iOS decides to suspend your app the scanning stops. I have seen this happen as soon as 30 seconds if there are a bunch of apps running.

Jon Vogel
  • 5,244
  • 1
  • 39
  • 54