BLE Scanning

iOS BLE Background Scanning Stops After Few Minutes to Hours

Hi everyone,

I'm developing a Flutter app using flutter_blue_plus that needs continuous BLE scanning in both foreground and background. Foreground scanning works perfectly, but background scanning stops after a few minutes (sometimes 1-2 hours).

Current Implementation (iOS)

Foreground Mode:

  • Scans for 10 seconds with all target service UUIDs
  • Batches and submits results every 10 seconds
  • Works reliably ✅

Background Mode:

  • Rotates through service UUIDs in batches of 7
  • Uses 1-minute batch intervals
  • Maintains active location streaming (Geolocator.getPositionStream)
  • Switches modes via AppLifecycleState observer
// Background scanning setup
await FlutterBluePlus.startScan(
  withServices: serviceUuids,  // Batch of 7 UUIDs
  continuousUpdates: true,
);

// Location streaming (attempt to keep app alive)
LocationSettings(
  accuracy: LocationAccuracy.bestForNavigation,
  distanceFilter: 0,
);

Lifecycle Management:

AppLifecycleState.paused -> Start background mode
AppLifecycleState.resumed -> Start foreground mode

Questions:

  1. Is there a documented maximum duration for iOS background BLE scanning? My scanning stops inconsistently (few minutes to 2 hours).

  2. Does iOS require specific Background Modes beyond location updates to maintain BLE scanning? I have location streaming active but scanning still stops.

  3. Are there undocumented limitations when scanning with service UUIDs in background that might cause termination?

  4. Should I be using CoreBluetooth's state preservation/restoration instead of continuous scanning?

Info.plist Configuration:

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

Additional Context:

  • Total service UUIDs: ~20-50 (varies by company)
  • Scanning in batches of 7 to work around potential limitations
  • Android version works fine with foreground service
  • Location permission: Always
  • iOS 14+ target

Any insights on iOS BLE background limitations or best practices would be greatly appreciated.

Thanks!

BLE scanning does not stop in the background. But it slows down. So for your situation, what is probably happening is:

  1. while you are juggling your scanning batches, stopping one and starting the other, it is possible that your app is not being able to start the next batch after stopping the previous one. If that happens, you would have stopped the scan but was never able to restart the other for one reason or another. If you believe the scan has actually stopped, you may want to double check the next batch was able to have started, perhaps confirm by logging the start if the next batch and see if you get there. And if you confirm the scan never starts, then debug why this is occurring.
  2. the scan is not stopping, but because it slows down when the app is in the background, you think it has stopped due to the inability to discover advertising peripherals. This is a standard behavior of iOS and the only solution would be to increase the advertising frequency of the peripherals. If the advertising interval is not small enough, it could take minutes to discover a device. What you can do is to set the advertising intervals to 20 ms, and see if the app in the background would then be able to discover the peripherals within 30 seconds. If that works, that means the scan is not stopping, but slowing down (as expected) enough that you are thinking it did stop. If that turn out to be the case, there is nothing you can do to affect the scan rate, and your only solution would be to decrease the peripherals' advertising intervals, if you are not able to keep a component of the app active in the foreground. As I will expand below, all apps in the background have the possibility of being terminated by the system. And if this happens in between stopping one batch and starting the next, then you would be stuck in a no-scan phase.

The background location models nothing to do with BLE scanning in the background. For that you need the bluetooth-central background key, which you say you do.

You should be using state preservation/restoration anyways, in case the app gets terminated in the background. All apps are targets for termination in the background if the system needs the resources it is using. There is also no way to prevent this. What you can do is implement protections, like Bluetooth restoration, so the system continues scanning on your behalf, and restore your app when it an event requiring a response from your app occurs. If your app gets terminated in the background while scanning, the system will continue the scan on your behalf indefinitely. But in your case, this means it will be scanning of the last 7 UUIDs that you started scanning for. You will not be able to switch to the next batch, because your app won't be launched by restoration if nothing happens with that scan.

If your app is getting relaunched due to location after termination, make sure the Bluetooth state is restored, as you will not get a willRestoreState() callback as in the case of your app being relaunched due to Bluetooth restoration.


Argun Tekant /  WWDR Engineering / Core Technologies

BLE Scanning
 
 
Q