From 773a17cc432fc981e5963f3635cd787356f76ffe Mon Sep 17 00:00:00 2001 From: Jonas Bark Date: Thu, 25 Jun 2026 15:43:25 +0200 Subject: [PATCH] feat(darwin): notify central of background connection events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set CBConnectPeripheralOptionNotifyOnConnection/Disconnection/Notification on connect() so CoreBluetooth surfaces connection, disconnection and notification events that occur while the app is suspended (relaunching it into the background to handle them). This keeps a backgrounded central — e.g. a fitness app reconnecting to a previously paired trainer — responsive without the user having to foreground the app. Consolidated to a single manager.connect(options:) call; the iOS 17+ auto-reconnect option is merged into the same dictionary, so behavior on that path is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../universal_ble/UniversalBlePlugin.swift | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/darwin/universal_ble/Sources/universal_ble/UniversalBlePlugin.swift b/darwin/universal_ble/Sources/universal_ble/UniversalBlePlugin.swift index 10f8c871..968e3a6b 100644 --- a/darwin/universal_ble/Sources/universal_ble/UniversalBlePlugin.swift +++ b/darwin/universal_ble/Sources/universal_ble/UniversalBlePlugin.swift @@ -211,11 +211,24 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral peripheral.delegate = self let shouldAutoConnect = autoConnect ?? false + // Ask the system to surface connection-related events while the app is + // suspended (relaunching it into the background when one occurs), so a + // backgrounded central stays responsive — e.g. while reconnecting to a + // previously paired peripheral — without the user having to foreground the + // app. Apple gates this behind per-connection options: + // - NotifyOnConnectionKey: a connection succeeded + // - NotifyOnDisconnectionKey: the peripheral disconnected + // - NotifyOnNotificationKey: a characteristic notification arrived + var options: [String: Any] = [ + CBConnectPeripheralOptionNotifyOnConnectionKey: true, + CBConnectPeripheralOptionNotifyOnDisconnectionKey: true, + CBConnectPeripheralOptionNotifyOnNotificationKey: true, + ] + if shouldAutoConnect { autoConnectDevices.insert(deviceId) if #available(iOS 17.0, macOS 14.0, watchOS 10.0, tvOS 17.0, *) { - let options: [String: Any] = [CBConnectPeripheralOptionEnableAutoReconnect: true] - manager.connect(peripheral, options: options) + options[CBConnectPeripheralOptionEnableAutoReconnect] = true } else { // Auto-reconnect via CBConnectPeripheralOptionEnableAutoReconnect is only // available on iOS 17.0 / macOS 14.0 / watchOS 10.0 / tvOS 17.0 and later. @@ -228,12 +241,12 @@ private class BleCentralDarwin: NSObject, UniversalBlePlatformChannel, CBCentral "is only available on iOS 17+/macOS 14+/watchOS 10+/tvOS 17+. " + "On this OS version, reconnections must be handled manually." ) - manager.connect(peripheral) } } else { autoConnectDevices.remove(deviceId) - manager.connect(peripheral) } + + manager.connect(peripheral, options: options) } func disconnect(deviceId: String) throws {