Improve iPhone↔Mac connection reliability#1
Merged
Conversation
The MultipeerConnectivity link between the iPhone and Mac dropped commands and reconnected unreliably. This addresses the main causes: - Mac now recreates its MCSession on full disconnect (it previously reused a possibly half-dead session for the next invitation, while the iPhone always recreated its own — an asymmetry that caused flaky reconnects). - Bidirectional keepalive + watchdog: the Mac now ACKs keepalives, and both sides tear down and cleanly reconnect when no traffic arrives for ~9s. This detects half-open links that MCSession still reports as `.connected`. - Guard against overlapping invitations (the reconnect timer and browser(foundPeer:) could both invite the same Mac at once, bouncing the connection). - Persist MCPeerID across launches (Apple's recommendation) to avoid phantom/duplicate peers and stabilize reconnection-by-name. - Exponential backoff with jitter on reconnect instead of a fixed 1s retry; invite timeout shortened 30s → 15s for faster recovery. The persistent-peer helper is guarded with `#if canImport(MultipeerConnectivity)` since the Shared sources also compile into the watchOS target, where the framework is unavailable. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0111bgqmC4myR1hzdTBio4ri
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The MultipeerConnectivity link between the iPhone and Mac was unstable — commands occasionally dropped and reconnects were unreliable. Reviewing both connection managers surfaced several concrete causes.
What changed
1. Mac recreates its session on disconnect (biggest fix)
Previously the iPhone recreated its
MCSessionon every drop but the Mac reused its old one for the next invitation. After a drop that session can be left half-dead, so the next connection was flaky. The Mac now recreates a clean session on full disconnect, mirroring the iPhone.2. Bidirectional keepalive + stale-link watchdog
The keepalive was fire-and-forget (iPhone → Mac, no reply), so neither side could tell a "connected" session had actually gone dead. Now:
keepaliveAck.This catches half-open links that
MCSessionstill reports as.connected— the usual cause of silently-dropped slide commands.3. Duplicate-invitation guard
The reconnect timer and
browser(foundPeer:)could both invite the same Mac at once, which makes MultipeerConnectivity bounce the connection. Invitations are now guarded by an in-flight flag.4. Persistent
MCPeerIDBoth apps created a fresh
MCPeerIDeach launch. Apple recommends reusing one — a new ID with the same display name is treated as a different peer, causing phantom/duplicate peers and confusing reconnection-by-name. It's now archived toUserDefaultsand reused.5. Reconnect backoff + faster invite timeout
Fixed 1s retry replaced with exponential backoff + jitter (1→2→4→8s capped). Invite timeout shortened 30s → 15s so a stuck invitation no longer blocks reconnection for half a minute.
Notes
#if canImport(MultipeerConnectivity)becauseShared/also compiles into the watchOS target, where the framework isn't available.switchoverRemoteCommandexists outside the enum itself, which was updated for the newkeepaliveAckcase.Testing
DeckMacandDeckiOSschemes locally and verify a real iPhone↔Mac connect / drop / reconnect cycle before merging.🤖 Generated with Claude Code
Generated by Claude Code