Issue with Bluetooth Background Scanning on iOS 15.7.3. BLE. Swift

I'm facing an issue with background scanning of Bluetooth on devices with iOS 15.7.3. I'm developing an application that needs to discover BLE devices even in the background mode. However, the didDiscover method is not getting called during background scanning.

Here's what I've already checked and configured in my project:

  • Appropriate permissions for Bluetooth usage and background processing are in place.
  • Flags in the project settings for background processing are configured correctly.
  • I've verified that BLE devices are set up for advertising in the background.
  • There are no physical obstacles or interference; devices and BLE devices are in an open environment.

Additional details and conditions:

  • The application initiates background scanning in the applicationDidEnterBackground method.
  • At the beginning of the test, the BLE device is not accessible. I bring it near the iPhone after approximately 5 minutes of the app being in the background.
  • If I don't move the BLE device away from the iPhone, it is detected almost immediately after the app goes into the background, but only once.
  • The phone screen doesn't lock during the test.
  • The CBCentralManagerOptionRestoreIdentifierKey option is used in the CBCentralManager.
  • On an iPhone 12 mini with iOS 16.3.1, background scanning works, but the device is found only once for call scanForPeripherals method.
  • The following filters are used: CBUUID(string: "330C5AD1-7261-4F06-B87C-0F6342365C2E") and CBUUID(string: "4c6607e0-2c3d-4fca-b201-0246773d6e9c").
  • If during the test you go to the Bluetooth settings of the iPhone (where there is a search for devices), the didDiscover method begins to report found devices
  • Advertisement data for BLE looks like this
7 elements
0 : 2 elements
key : "kCBAdvDataServiceUUIDs"
value : 1 element
0 : 4C6607E0-2C3D-4FCA-B201-0246773D6E9C
1 : 2 elements
key : "kCBAdvDataRxSecondaryPHY"
value : 0
2 : 2 elements
key : "kCBAdvDataTimestamp"
value : 719149435.0168051
3 : 2 elements
key : "kCBAdvDataLocalName"
value : GB3_0CCE
4 : 2 elements
key : "kCBAdvDataRxPrimaryPHY"
value : 0
5 : 2 elements
key : "kCBAdvDataServiceData"
value : 1 element
0 : 2 elements
key : 330C5AD1-7261-4F06-B87C-0F6342365C2E
value : \<01020304\>
6 : 2 elements
key : "kCBAdvDataIsConnectable"
value : 1

Here is a link to the repository with the test application. This is a test application that I use for testing. The repository contains code that is not needed for testing. The required classes for testing are AppConfiguration, BackgroundScanManager, and BackgroundBLEManager.

After bringing the BLE device near the iPhone, I wait for approximately 15-20 minutes.

Please, help me understand why the didDiscover method is not being called in the background mode on iOS 15.7.3. Perhaps someone has encountered a similar problem and can provide advice or recommendations?

Thank you very much!

For starters, receiving only a single callback for a discovered device when the app is not in the foreground is by design. If the app is not active in the foreground there will be only one didDiscover() callback per scanForPeripherals() call per peripheral.

As for not receiving any didDiscover() callbacks on some devices when in the background, putting aside the possibility that there might be some coding error that is causing the scan to stop or be abandoned, the most common cause for this is improper advertising. When the app is in the background two things happen:

  1. the scan rate drops, and if the peripheral is not advertising at a rate that will make it viable for the phone to discover the advertisements in a timely manner, you may experience this issue. The best way to test this hypothesis is to change the advertising interval of the peripheral to 20 ms, and see if that solves the issue. If it does, then the issue is the advertising interval, and you would need to pick an interval fast enough to work for the app, and the peripheral's battery consumption. The recommended advertising intervals that will give the best power to discovery ratios are: 20 ms, 152.5 ms, 211.25 ms, 318.75 ms, 417.5 ms, 546.25 ms, 760 ms, 852.5 ms, 1022.5 ms, 1285 ms

Even with these specific intervals, very slow rates may cause discovery to be too slow for your use case.

  1. the iOS device may go into a passive scan mode, in which case it will observe the ADV_IND packets, but will not request the SCAN_RSP packets. In this state, if the service UUID that you app is scanning for is not contained in the ADV_IND packet but in SCAN_RSP, this will give iOS no opportunities to recognize the peripheral as one that should be reported to your app.

It is difficult to explain the differences you see in the behavior of two devices, whether they are due to iOS versions or device state (again putting aside for now that there could be some issue with the app that is being triggered differently). There could be a number of factors in play, but fixing peripheral advertising takes care of a large percentage of similar issues reported by developers.

Issue with Bluetooth Background Scanning on iOS 15.7.3. BLE. Swift
 
 
Q