CBCentralManager connection in background.

Hello,

I’m experiencing an issue with my iOS app that uses CoreBluetooth in combination with beacon monitoring. My app is designed to wake via beacon region monitoring and then start scanning for a specific BLE peripheral (with specific service UUIDs). When the device screen is bright (i.e., the device is unlocked, or locked but the screen is active/bright), everything works perfectly—the connection is established and maintained without any issues in both: foreground and background.

However, when the device is left alone for a while and the lock-screen dims (sleeps), the app continues to run in the background and range the beacon (I can confirm this via realtime console logs), but the connection attempt fails. Here’s what I observe:

The central manager’s delegate method didConnect is called, indicating that the peripheral was connected. Almost immediately afterward, didDisconnect is triggered with the error message: "The specified device has disconnected from us.". The interesting part is (I repeatedly see this error in the console, because the app repeatedly tries to connect to peripheral until a success), when I touch the lockscreen (not unlock, but just touch, which makes the screen to light up brighter), the connection is being established without any further issues!

I have the necessary background modes enabled in the app’s capabilities (e.g., bluetooth-central, location-always-mode, etc..). My expectation was that, thanks to beacon monitoring, the app would be awakened when needed, and scanning/connection would work reliably in the background regardless of whether the device is active or dimmed.

My questions are:

Why might the connection fail with this error when the device is locked/dimmed? Is this behavior expected due to iOS power management policies even if the app remains active in the background?

Is there a way to ensure a reliable connection in such cases?

Any insights, workarounds, or suggestions would be greatly appreciated. Thank you in advance!

Answered by Engineer in 827707022

First, my best guess as to what's happening: - error message: "The specified device has disconnected from us."

This means exactly what it says. That the disconnection came from the outside. Either the peripheral disconnected, or you lost connection. Based on this happening all the time and immediately after connection, it is possible that your device is rejecting the connection parameters iOS is suggesting and dropping the connection. You should start by debugging this on your device side to find out why it is disconnecting.

iOS requires a specific set of connection parameters, and will reject anything that does not comply.

These rules are described in Accessory Design Guidelines for Apple Products

Connection parameter requests may be rejected if they do not meet the guidelines in this section. General connection parameter request guidelines:

  • Peripheral Latency ≤ 30 connection intervals.
  • Supervision Timeout from 6 seconds to 18 seconds.
  • Interval Min ≥ 15 ms.
  • Interval Min ≤ 2 seconds.
  • Interval Min is a multiple of 15 ms.
  • One of the following:
    • Interval Max at least 15 ms greater than Interval Min.
    • Interval Max and Interval Min are both 15 ms.
  • Interval Max * (Peripheral Latency + 1) of 6 seconds or less.
  • Supervision Timeout greater than Interval Max * (Peripheral Latency + 1) * 3.

Even if your peripheral is requesting these parameters, iOS may still reject them and instead suggest another set of parameters.

My guess is one of two things are happening:

  • your peripheral is outright rejecting the connection because iOS did not accept the parameters it asked for
  • the peripheral is not compatible with whatever parameters have been negotiated, and that is causing issues/errors and dropping the connection.

What parameters iOS will accept may indeed vary depending on the device and app state. So, your peripheral should be ready for any set of parameters.

But debugging your peripheral side should answer what the problem might be. The parameters are controlled by the system and your app code cannot change or effect change on them in any way.

While here, let me touch on some red flags in your message. These may or may not be contributing to the problem, but could possibly cause issues or worse, misplaced expectations on behavior by you.

- programmed to advertise both peripheral data and iBeacon data

Assuming you only have one BT chip, and it does not have the ability to change its address on demand (consumer chipsets that can do this is rare), the only way this will work without issues is if you are using BLE 5 Advertising Sets for different types of advertising. Without these, you will mess up the deduping logic on device, and things may fail in random ways.

--

- the app continues to run in the background and range the beacon

While you can start and range for beacons when the app is in the background, simply ranging will not keep your app running in the background, and the app will be suspended after a short while. Only if you are using an alternate method that is able to keep the app running, like full background location updates, then you would also be able to continue ranging.

So, you are either mistaken and the app is not running for more than approximately 10 seconds, or you are using something else to keep the app running. If the latter, what is it, and how much power and CPU is this using?

--

- The central manager’s delegate method didConnect is called, indicating that the peripheral was connected.

If this is happening, then you are past many of the hurdles due to slowdown in scanning, and passive scan when your app is not in the foreground. Congratulations. But you may not be in the clear yet.

--

- the app would be awakened when needed, and scanning/connection would work reliably in the background regardless of whether the device is active

For Bluetooth, what matters is the app is in the foreground. The performance will drop once it is no longer, whether it is kept running by another trick or not.


Argun Tekant /  DTS Engineer / Core Technologies

For more context:

The BLE peripheral in my setup is a custom ESP32 chip that we’ve programmed to advertise both peripheral data and iBeacon data. This chip will be integrated into smart lock systems (for buildings, garages, etc.), with the goal of automatically unlocking the door when a resident comes close. The idea is that the app runs in the background and, once it detects the beacon (via region monitoring) and gets awakened, it initiates a connection with the peripheral to exchange security keys. If the residential criterion is met, the ESP32 then unlocks the door.

First, my best guess as to what's happening: - error message: "The specified device has disconnected from us."

This means exactly what it says. That the disconnection came from the outside. Either the peripheral disconnected, or you lost connection. Based on this happening all the time and immediately after connection, it is possible that your device is rejecting the connection parameters iOS is suggesting and dropping the connection. You should start by debugging this on your device side to find out why it is disconnecting.

iOS requires a specific set of connection parameters, and will reject anything that does not comply.

These rules are described in Accessory Design Guidelines for Apple Products

Connection parameter requests may be rejected if they do not meet the guidelines in this section. General connection parameter request guidelines:

  • Peripheral Latency ≤ 30 connection intervals.
  • Supervision Timeout from 6 seconds to 18 seconds.
  • Interval Min ≥ 15 ms.
  • Interval Min ≤ 2 seconds.
  • Interval Min is a multiple of 15 ms.
  • One of the following:
    • Interval Max at least 15 ms greater than Interval Min.
    • Interval Max and Interval Min are both 15 ms.
  • Interval Max * (Peripheral Latency + 1) of 6 seconds or less.
  • Supervision Timeout greater than Interval Max * (Peripheral Latency + 1) * 3.

Even if your peripheral is requesting these parameters, iOS may still reject them and instead suggest another set of parameters.

My guess is one of two things are happening:

  • your peripheral is outright rejecting the connection because iOS did not accept the parameters it asked for
  • the peripheral is not compatible with whatever parameters have been negotiated, and that is causing issues/errors and dropping the connection.

What parameters iOS will accept may indeed vary depending on the device and app state. So, your peripheral should be ready for any set of parameters.

But debugging your peripheral side should answer what the problem might be. The parameters are controlled by the system and your app code cannot change or effect change on them in any way.

While here, let me touch on some red flags in your message. These may or may not be contributing to the problem, but could possibly cause issues or worse, misplaced expectations on behavior by you.

- programmed to advertise both peripheral data and iBeacon data

Assuming you only have one BT chip, and it does not have the ability to change its address on demand (consumer chipsets that can do this is rare), the only way this will work without issues is if you are using BLE 5 Advertising Sets for different types of advertising. Without these, you will mess up the deduping logic on device, and things may fail in random ways.

--

- the app continues to run in the background and range the beacon

While you can start and range for beacons when the app is in the background, simply ranging will not keep your app running in the background, and the app will be suspended after a short while. Only if you are using an alternate method that is able to keep the app running, like full background location updates, then you would also be able to continue ranging.

So, you are either mistaken and the app is not running for more than approximately 10 seconds, or you are using something else to keep the app running. If the latter, what is it, and how much power and CPU is this using?

--

- The central manager’s delegate method didConnect is called, indicating that the peripheral was connected.

If this is happening, then you are past many of the hurdles due to slowdown in scanning, and passive scan when your app is not in the foreground. Congratulations. But you may not be in the clear yet.

--

- the app would be awakened when needed, and scanning/connection would work reliably in the background regardless of whether the device is active

For Bluetooth, what matters is the app is in the foreground. The performance will drop once it is no longer, whether it is kept running by another trick or not.


Argun Tekant /  DTS Engineer / Core Technologies

CBCentralManager connection in background.
 
 
Q