BLE advertising/scanning communication broken on iPhone 17 — CBPeripheralManager + CBCentralManager workflow

Environment:

iPhone 17 / iPhone 17 Pro (Apple N1 chip) iOS 26.x Xcode 26 Framework: Flutter app with native iOS BLE library (CoreBluetooth)

We have a production IoT app that communicates with BLE nodes (Nordic, PIC, EnOcean peripherals) using an advertising/scanning-based protocol — not GATT connections. The app broadcasts commands via CBPeripheralManager (advertising service UUIDs) and receives responses by scanning with CBCentralManager (reading manufacturer data and service UUIDs from advertisement packets). This workflow has been reliable across all iPhone models from iPhone 8 through iPhone 16 Pro Max.

On iPhone 17 devices, we are experiencing multiple failures in this workflow.

Architecture:

Sending commands: We use CBPeripheralManager.startAdvertising() with CBAdvertisementDataServiceUUIDsKey to broadcast a UUID-encoded command to nearby nodes.

Receiving responses: We use CBCentralManager.scanForPeripherals(withServices: nil, options: [CBCentralManagerScanOptionAllowDuplicatesKey: true]) and filter responses in centralManager(_:didDiscover:advertisementData:rssi:) by matching CBAdvertisementDataServiceUUIDsKey or CBAdvertisementDataManufacturerDataKey against expected UUID masks.

Communication pattern: Advertise a command → stop advertiser → start scanner → wait for matching response → process result. Typical timeout is 1.5 seconds per exchange.

Issues observed on iPhone 17:

  1. peripheralManagerDidStartAdvertising behaviour change

After calling CBPeripheralManager.startAdvertising(:), the delegate callback peripheralManagerDidStartAdvertising(:error:) either fires with errors that did not occur on previous hardware, or advertising does not appear to reach the peripheral nodes at all. The same advertising payload works immediately when tested on iPhone 15/16.

Is the N1 chip's Bluetooth 6 stack handling CBAdvertisementDataServiceUUIDsKey advertising differently? Are there new constraints on advertising payload size or format?

  1. Scanner returning fewer/no results with withServices: nil

Our scanner uses scanForPeripherals(withServices: nil) because we need to read manufacturer data from advertisement packets and filter using a custom UUID mask. On iPhone 17, we observe significantly fewer didDiscover callbacks compared to iPhone 15/16 in the same physical environment, with the same nodes advertising.

We understand that passing service UUIDs in withServices: is recommended, but our protocol requires reading raw manufacturer data bytes that aren't associated with a single service UUID — we use mask-based matching (e.g., filter mask 11110000-0000-0000-0000-000000000000 against scan results).

Has the N1 chip changed the rate or filtering behaviour of unfiltered BLE scans? Is there a new throttling mechanism?

  1. Background scanning stops immediately

When the app moves to background, scanning appears to stop entirely on iPhone 17 — even with bluetooth-central in UIBackgroundModes. On iPhone 16, background scanning continued (at reduced intervals) and delivered results for peripherals advertising filtered service UUIDs.

  1. Aggressive session termination on app backgrounding

Our advertise-then-scan sequences (typically 1.5s round-trip) are being interrupted when the user briefly switches apps. The CBPeripheralManager stops advertising and the CBCentralManager stops scanning, causing timeout errors. This was not observed on previous iPhone models with the same iOS background mode configuration.

Questions for Apple:

Are there documented changes to CoreBluetooth behaviour on the N1 Bluetooth 6 chip that affect advertising-based (non-GATT) communication patterns? Has the scan response rate for scanForPeripherals(withServices: nil) been intentionally reduced on iPhone 17? Is CBCentralManagerOptionRestoreIdentifierKey now required for reliable background scanning on iPhone 17, or is this a known regression? Are there new advertising payload constraints (size, format, interval) that we should be aware of for the N1 chip? What we've tried:

Added NSBluetoothAlwaysUsageDescription and NSBluetoothWhileInUseUsageDescription to Info.plist Confirmed Bluetooth permissions are granted Tested with identical BLE nodes that work on iPhone 15/16 Verified CBManagerState.poweredOn before all operations Any guidance or known workarounds would be greatly appreciated. Happy to provide sysdiagnose logs or a minimal reproducible sample project.

There have been some behavioral changes on N1 chip devices; especially in areas where the BT spec has not had a single way of interpreting things. We have been observing these changes and changing them back if appropriate and are considered regressions. So, the first thing you should do is to test all this in the latest iOS 26.3 and see if anything has changed from your earlier observations.

Also, there would have been some changes on patterns of use that were never meant to work, but just happened to work, and those would have been corrected. For example, scanning without services is not supposed to work, and was never expected to work in the background. If you are scanning in the background without services, and whatever the Flutter library may have been doing to work around that limitation (if anything), and that has stopped working, you can consider that a bug that has been fixed.

Similarly, advertising packets in the background have always been on a best effort basis. Also, it has always been possible that due to resource limitations, advertised data could have been hashed into an overflow area, only readable by other Apple devices. If this is happening more often, that would not be necessarily due to the N1 chip changes, but general resource limitations that happen to occur on those devices.

In any case, these need a closer look, and also you may want to look into whether the Flutter library may have anything to do with the issues.

So, we will need more information on all these issues, with sysdiagnoses (with Bluetooth logging profile installed), and the best way to send those over will be via a Bug Report, or several for the different issues, so each can get routed to the appropriate team for the issue.

For each of these issues, please file a separate bug report, include repro steps, and the sysdiagnose from an N1 device and from an earlier device. Also include your reproducible sample project. And please answer the following questions for each issue.

1. peripheralManagerDidStartAdvertising behaviour change What are the errors you are seeing? When you say the advertising is not reaching, have you seen this with a sniffer? Is this during background advertising? If you have logs from the receiving device add those as well. We need to understand if advertising is not being sent out, or this is an interpretation issue with the receiving device.

2. Background scanning stops immediately If you are scanning without services, this is expected behavior, regardless of what you may have observed earlier. If you are scanning with services, the scanning will not stop but slow down. Unless the peripheral is advertising fairly fast, you may be observing a delay rather than a stop. Also, when in the background, didDiscoverPeripheral() will only get called once per scan per peripheral. If the Flutter library has been doing something to workaround this limitation (we see this often), that may have stopped working. In any case, this will need some more debugging on your end, and if you determine this is an issue not with your implementation (library or otherwise), than you could file bug report on this as well.

3. Aggressive session termination on app backgrounding Have you confirmed that your app is staying in the background and not being terminated while in the background? Again, this would not have anything to do with the N1 chip, but the system might be terminating your app due to general resource constraints, not necessarily having to do with Bluetooth. Have you implemented Bluetooth State Preservation/Restoration in your app to make sure the system scans and advertises on your behalf even after your app is terminated?

So, check that the issues are not due to your code/library/target that happens to be exposed on the new phones, and if you believe these should be looked at by the Bluetooth team, please file the bug reports as I explained above, and share the Feedback IDs here. And @mention me in your response, and I will make sure they are routed to the appropriate teams.


Argun Tekant /  WWDR Engineering / Core Technologies

this is actually happening when we do self.peripheralManager?.startAdvertising(self.uuidData) ? do you have any idea.?

  func startAdvertiser(uuid: CBUUID, timeout: Double) -> Single<AdvertiserErrorCode> {
        return Single.create { emitter in
            Utils.blePrint("@startAdvertiser uuid: \(uuid.uuidString), timeout: \(timeout), state: \(self.peripheralManager?.state.rawValue ?? -1), isAdvertising: \(self.advertising)")
            if (self.peripheralManager?.state == CBManagerState.poweredOn) {
                self.timeout = timeout
                self.uuidData = [
                    CBAdvertisementDataServiceUUIDsKey: [uuid]
                ]
                self.emitter = emitter
                self.restartAdvertising()
            } else {
                Utils.blePrint("@startAdvertiser BT not powered on, state: \(self.peripheralManager?.state.rawValue ?? -1)")
                emitter(.success(AdvertiserErrorCode.BLUETOOTH_NOT_ON))
            }
            return Disposables.create {

            }
        }
    }

What is this you say is happening? And there is no startAdvertising() call in your included snippet.

BLE advertising/scanning communication broken on iPhone 17 — CBPeripheralManager &#43; CBCentralManager workflow
 
 
Q