Unexpected CoreBluetooth background suspension without active location updates

I am implementing BLE scanning and connection using CoreBluetooth in a Flutter application with native iOS Swift code.

BLE scanning and connection work correctly in the foreground and for a short time after the app is sent to the background. However, after some time in the background, BLE scanning stops and the device is no longer discovered. The app appears to be suspended by iOS.

Key Observation: When location services are actively in use (navigation arrow visible in the iOS status bar), BLE scanning and reconnection work reliably in the background. When location services are not actively running, BLE scanning stops in the background even though the app has “Always Allow” location permission. Expected Result BLE scanning and connection should continue to function in the background using the Bluetooth LE background mode, without relying on active location updates. Actual Result BLE scanning starts successfully App enters background After some time, scanning stops Device is no longer discovered BLE works again only if location services are actively running BLE Connection Behavior One-time scan connects successfully to a BLE medical device App is sent to background Existing connection does not disconnect However, new scans or reconnections fail once the app is suspended Relevant Native iOS Code (AppDelegate) import Flutter import UIKit import CoreBluetooth

@main @objc class AppDelegate: FlutterAppDelegate {

private var backgroundTaskID: UIBackgroundTaskIdentifier = .invalid

override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {

    GeneratedPluginRegistrant.register(with: self)

    if let identifiers =
        launchOptions?[UIApplication.LaunchOptionsKey.bluetoothCentrals] as? [String] {
        print("App relaunched for BLE state restoration: \(identifiers)")
    }

    NotificationCenter.default.addObserver(
        self,
        selector: #selector(appDidEnterBackground),
        name: UIApplication.didEnterBackgroundNotification,
        object: nil
    )

    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}

@objc private func appDidEnterBackground() {
    backgroundTaskID = UIApplication.shared.beginBackgroundTask {
        self.endBackgroundTask()
    }
}

private func endBackgroundTask() {
    if backgroundTaskID != .invalid {
        UIApplication.shared.endBackgroundTask(backgroundTaskID)
        backgroundTaskID = .invalid
    }
}

}

Questions for DTS: Is it expected behavior that CoreBluetooth background scanning effectively stops once the app is suspended, even when the Bluetooth LE background mode is enabled? Why does BLE background scanning appear to work reliably only when location services are actively running? Is iOS internally associating BLE background execution with active location updates?

For continuous BLE reconnection (medical device use case), is the recommended approach to rely solely on CoreBluetooth state restoration instead of continuous background scanning? Is it considered best practice to avoid long-running BLE scans in the background and instead wait for system-delivered BLE events?

Additional Notes Issue is reproducible on real devices Not using private APIs or unsupported background execution methods Objective is to follow Apple-recommended, App Store–compliant behavior

No, the scanning will not stop, but will slow down by a lot when the app is no longer in the foreground.

CoreLocation and CoreBluetooth don't have any relation to each other as far as the capabilities go. If you are seeing a difference in CoreBluetooth behavior based on CoreLocation state, you should consider that as an unintended undocumented side effect and not rely on that observed effect for your product.

The reason you might be thinking the scanning is stopping when the app is not in the foreground would be due to the slowed down scan rate for your app, the discovery of the advertising device is taking longer than you expect.

The recommended advertising intervals for best power to time-of-discovery 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 when using these intervals, it may take more than you expect if you are using one of the higher values.

What I would suggest is to first set the advertising interval to 20ms to confirm that your app's architecture is not causing the scan to stop, and then use increasing values until the time to discovery you observe is acceptable for the power drain it would result on the device.

Other possible causes for background scanning issues is if your app is scanning for a service or information (like the device name, manufacturer info, etc.) that happens to be advertised in the secondary advertising packet (SCAN_RSP), you could be missing that information, end up ignoring the discovered device, and assume the scan is not working.

What I would suggest is to first simply use CoreBluetooth without attached CoreLocation shenanigans, and make sure the scan works in the background with the advertising settings of the accessory you are scanning for. And then you can add whatever you think would be beneficial to your use case.

SUB : iBeacon Monitoring in Flutter App: Background Wake-Up from Killed State, Time Limits for BLE, and Handling Multiple Regions/Identifiers

Hello Engineer, I'm developing a cross-platform app using Flutter and the flutter_beacon library to handle iBeacon detection on iOS. My goal is to wake up the app in the background when it's in a killed/terminated state upon entering/exiting beacon regions, allowing for BLE communication (e.g., ranging or connecting to beacons). I've configured the necessary Info.plist keys for always location access and background location modes, and it works partially for single regions, but I have some specific questions/issues regarding reliability and limitations: Background Execution Time After Wake-Up: When the app is woken in the background by a region monitoring event (enter/exit) from a killed state, approximately how much time (in seconds) does iOS allocate for the app to run before suspending it again? Is this sufficient for performing BLE operations like ranging beacons or establishing a short connection, or are there stricter limits in terminated wake-ups compared to standard background modes? Monitoring Multiple iBeacons with Unique Identifiers: I need to monitor multiple iBeacon devices, each with potentially different UUIDs, majors, and minors. Can I add and monitor up to 20 regions simultaneously, each with a unique string identifier? If multiple beacons (from different regions) enter their respective ranges at around the same time, will the app receive separate callbacks for each region/identifier, or is there coalescing/prioritization that might cause only the last-added identifier to trigger notifications/events? Reliability in Killed State: In a fully killed state (e.g., force-quit via app switcher), does iOS reliably relaunch the app in the background for region monitoring events? Are there any known caveats, such as requiring specific hardware (e.g., iPhone models with certain Bluetooth chips) or iOS versions (targeting iOS 14+), and how does this interact with Flutter's background execution handling via the flutter_beacon library?

Unexpected CoreBluetooth background suspension without active location updates
 
 
Q