Skip to content

fix: adopt already-connected peripheral instead of stranding at "(Pairing…)"#39

Merged
MegaManSec merged 1 commit into
mainfrom
fix/reclaim-already-connected
Jun 3, 2026
Merged

fix: adopt already-connected peripheral instead of stranding at "(Pairing…)"#39
MegaManSec merged 1 commit into
mainfrom
fix/reclaim-already-connected

Conversation

@MegaManSec
Copy link
Copy Markdown
Owner

Problem

The auto-reconnect watcher (#36) can leave a peripheral stuck showing (Pairing…) in the menu forever, even though it is actually connected and working.

The reclaim path (reclaimIfPeerIsFree) does a HOLDS_ONE network round-trip to the peer before deciding to re-pair. During that window macOS frequently reconnects the bonded device on its own. By the time connectPeripheral runs, the device is already connected — but connectPeripheral only checked Bluetooth power and RSSI, never isConnected(), so it still started an IOBluetoothDevicePair. Pairing an already-connected device never fires devicePairingFinished, so the state machine is stranded at .connecting.

Fix

Short-circuit in connectPeripheral: if the device is already connected, adopt the live connection (set .connected, register the disconnect observer so a future genuine drop re-arms the watcher) instead of pairing. The watcher then disarms on its next tick.

Placing the check in connectPeripheral rather than just the watcher path also protects the interactive takePeripheralFromPeer / per-peripheral menu paths from the same stranding.

Testing

  • xcodebuild ... CODE_SIGNING_ALLOWED=NO build succeeds.
  • swift format leaves the change untouched.

…ring…)"

The auto-reconnect watcher's reclaim path does a HOLDS_ONE network
round-trip to the peer before deciding to re-pair. macOS often
reconnects the bonded device on its own during that window, so by the
time connectPeripheral runs the device is already connected. Starting an
IOBluetoothDevicePair on an already-connected device never fires
devicePairingFinished, stranding the state machine at .connecting — the
menu shows "(Pairing…)" forever even though the peripheral works.

Short-circuit in connectPeripheral: if the device is already connected,
adopt the live connection (set .connected, register the disconnect
observer) instead of pairing. Covers the interactive take/menu paths too.
@MegaManSec MegaManSec merged commit 22039fa into main Jun 3, 2026
@MegaManSec MegaManSec deleted the fix/reclaim-already-connected branch June 3, 2026 14:46
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 3, 2026

🎉 This PR is included in version 2.11.2 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant