3

I Just crate my advertisement peripheral with Service & Characteristic UUID

Here is my Service & Characteristic UUID

let kTRANSFER_SERVICE_UUID                = “29ada058-c7d6-4ed5-bc7f-1c7b0458b3b8”                                   
let kTRANSFER_CHARACTERISTIC_UUID = “91e032f2-c915-47c6-a8d9-6b3bc6c8e73d”

Now I create instance of CBPeripheralManager

private var peripheralManager: CBPeripheralManager!
private let beaconOperationsQueue = DispatchQueue(label: "beacon_operations_queue")
private let option = [CBCentralManagerScanOptionAllowDuplicatesKey:true]

// Assign peripheralManager with Queue & Option
peripheralManager = CBPeripheralManager(delegate: self, queue: beaconOperationsQueue, options: option)

Then I am calling this StartAdvertising method, But this will only work on Foreground Mode, Now I want to allow in Background Mode so for that I add the UIBackgroundModes key in Info.plist

 public func startAdvertising(serviceID: String, name: String) {

        let valueData = name.data(using: .utf8)

        self.serviceID = CBUUID(string: serviceID)
        self.peripheralName = name

        let CustomChar = CBMutableCharacteristic(type: CBUUID(string: kTRANSFER_CHARACTERISTIC_UUID), properties: [.read], value: valueData, permissions: [.readable])

        let myService = CBMutableService(type: self.serviceID, primary: true)
        myService.characteristics = [CustomChar]

        peripheralManager.add(myService)

        if self.peripheralManager.isAdvertising{

            self.peripheralManager.stopAdvertising()
        }
        peripheralManager.startAdvertising([
            CBAdvertisementDataServiceUUIDsKey: [serviceID],
            CBAdvertisementDataOverflowServiceUUIDsKey:[serviceID],
            CBAdvertisementDataLocalNameKey: peripheralName!])
    }

So when moving to the background than this will be happened

The CBAdvertisementDataLocalNameKey advertisement key is ignored, and the local name of peripheral is not advertised.

All service UUIDs contained in the value of the CBAdvertisementDataServiceUUIDsKey advertisement key are placed in a special “overflow” area; they can be discovered only by an iOS device that is explicitly scanning for them.

Also I was set “OverFlow” but still not work on background mode,

Can anyone guide for the same

Nik Jack
  • 87
  • 8
  • How do you know it isn't working in the background? What device/app are you using to discover your peripheral? – Paulw11 Apr 21 '20 at 20:27
  • We are using the BLE Scanner/NRF connect App into another Android/iOS device. In that we are trying to see the Peripheral device advertise by my iOS phone which is now running the app into background mode and in this case the the service and characterstics of my peripheral device is not showing into both App. This only work when my app is in forground mode. – Nik Jack Apr 22 '20 at 04:30
  • You will probably only be able to scan from another iOS device when your app is advertising from the background. You won't see services or characteristics in the scan data, only once you connect – Paulw11 Apr 22 '20 at 04:37
  • Yes we are connecting the device when iOS device running into background. But in this case the service and characterstics which i set that i am not able find when i am successful establish the connect with my iOS device running into backgroud. I am not sure which steps i am missing so i can find the my missing service and characterstics when i am connecting with iOS device. – Nik Jack Apr 22 '20 at 05:29
  • I would test with the LightBlue app on another iOS device. If it can see your characteristics and service then the problem isn't on your peripheral side; What code you have shown looks OK – Paulw11 Apr 22 '20 at 07:04
  • Also, to clarify, are you starting advertisement in the foreground and then moving the app to the background or are you trying to start advertising in the background? – Paulw11 Apr 22 '20 at 07:05
  • Yes, In light blue app it showing the device and I am able to connect with device but it is not showing the services or characteristics that I am advertising so looking for some needful help. – Nik Jack Apr 22 '20 at 07:11
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/212236/discussion-between-paulw11-and-nikhil-jobanputra). – Paulw11 Apr 22 '20 at 07:29

1 Answers1

10

Apple imposes restrictions on the way CoreBluetooth advertising and scanning works when apps are in the background. Unfortunately, this behavior is complex. Please bear with me.

For the purposes of this discussion background means any case where the app is not visible on the screen. (Phone locked, screen off, springboard shown, another app shown are all cases where an app is in the background.)

CBPeripheralManager GATT Service Advertising

  • In the background, service advertising changes to an Apple proprietary format that uses manufacturer advertisements that look like this: 0b ff 4c 00 10 06 57 1e fc 8a e1 7c. It doesn't matter whether advertising is started in the foreground and the app moves to the background, or advertising is started in the background. When advertising BLE apps are in the background, this advertisement uses this proprietary format.
  • The above advertisement does not contain the service UUIDs. Regardless of what is in CBAdvertisementDataServiceUUIDsKey, it will not appear in the advertisement.
  • The above advertisement does not contain the local name. Regardless of what is in CBAdvertisementDataLocalNameKey, it will not appear in the advertisement.
  • This advertisement works to communicate the specified service UUIDs from CBAdvertisementDataServiceUUIDsKey only to other iOS devices with a foregrounded app scanning with CBCentralManager. This works using an Apple proprietary technique. The actual service UUIDS are only provided by iOS in the "overflow area" upon request by the operating system when there is a foregrounded iOS app scanning. If there is no foregrounded iOS app scanning, this will not work as the actual service UUIDs will never be requested from the "overflow area".

CBCentralManager GATT Service Scanning

  • In the background, scanning without specifying a service UUID yields no results. If you have code like this: centralManager?.scanForPeripherals(withServices: nil, options: nil), nothing will match. You must explicitly specify the service UUIDs.

  • Attempting to request callbacks for multiple advertisements from the same device gets nothing as the CBCentralManagerScanOptionAllowDuplicatesKey option is ignored in the background. You will only get one callback the first time the device appears.

  • Scanning for a specific service UUID will succeed with at most one callback per the restriction above, only provided the advertising device is not a backgrounded iOS app.

  • If the advertising device is a backgrounded iOS app, then the advertisements will use the proprietary technique described above. Because the central is in the background, iOS will not request the overflow area from the backgrounded peripheral. No discovery callback will happen.

Then end result of this is that iOS to iOS GATT advertising and discovery works only when one of the two bluetooth apps is in the foreground. If both apps are in the background, new discoveries won't work. However, existing connections will continue to work and reconnect when both apps are in the background, and if a device disappears and reappears a new discovery callback will be provided. The key is that the discovery must have succeeded once when one of the two apps were in the foreground.

For the above to work, you do not need to set the CBAdvertisementDataOverflowServiceUUIDsKey when you begin advertising. Apple will automatically put any values for the key CBAdvertisementDataServiceUUIDsKey into the overflow area if the advertising app is in the background. The CBAdvertisementDataOverflowServiceUUIDsKey is read-only -- you can access this info upon receiving a scan result. You do not use it when advertising.

Interesting note: when you have more than two iOS device in this situation, a central and peripheral can discover each other when both are in the background provided there is a third iOS app scanning as a central in the foreground. That third iOS device can then make the request of the "overflow area", allowing the backgrounded iOS device to listen in on this and benefit by eavesdropping.

Android or other non-iOS devices can scan the proprietary iOS advertisement described above, and while they cannot see the Service UUIDs or request them from the "overflow area", they can connect anyway and then query the service UUIDs inside the connection. This is inefficient but it can work.

davidgyoung
  • 63,876
  • 14
  • 121
  • 204
  • Jep. This is all true. See also https://stackoverflow.com/questions/29418388/ble-advertising-of-uuid-from-background-ios-app. It was a pleasure to read http://www.davidgyoungtech.com/2020/05/07/hacking-the-overflow-area David. Well done. – Anne van Rossum Nov 30 '20 at 13:59