Skip to content

feat: pair a phone by scanning one code instead of copying two - #202

Merged
arzafran merged 2 commits into
mainfrom
feat/ios-pairing-one-scan
Jul 30, 2026
Merged

feat: pair a phone by scanning one code instead of copying two#202
arzafran merged 2 commits into
mainfrom
feat/ios-pairing-one-scan

Conversation

@arzafran

Copy link
Copy Markdown
Member

What this does

Setting up the phone used to mean copying two long opaque strings out of Mac
Settings and pasting them into two separate fields, with a five minute window
that gave no sign it was running out. That was the biggest thing between a new
tester and a working companion.

Now the Mac shows a QR code plus one combined link with a live countdown, and the
phone either scans it or takes a single paste. The old two-field path stays as a
fallback, so nothing breaks when the camera is unavailable.

There is also a README covering the two easy things to get wrong: the Mac toggle
is off by default, and both devices need the same iCloud account for background
notifications.

Summary

  • New combined pairing code programa-pair://pair?v=1&t=<ticket>&k=<token>, with
    a parser on each side. The two app targets share no module, so the copies are
    kept in sync by hand and both files say so.
  • Both sides validate v. A newer Mac cannot hand an older phone a format it
    would misread — the phone ships through TestFlight and will lag the Mac app, so
    that skew is the normal case, not an edge one.
  • beginPairing() now returns MobileBridgePairingInfo with a real expiresAt
    read from mobileBridgePairingWindowDuration, not a hardcoded 300s. That drives
    the countdown.
  • Mac Settings ▸ Phone: CoreImage QR, copyable link, countdown that flips to an
    expired state. Original ticket/token rows preserved behind a DisclosureGroup.
  • iOS: AVCaptureMetadataOutput scanner sheet handling the not-determined,
    denied and restricted permission states, degrading gracefully with no camera
    (simulator). NSCameraUsageDescription added inside info.properties only —
    mixing it with INFOPLIST_KEY_* silently drops keys, as project.yml:33-50
    documents.

Review order

  1. Sources/MobileBridge/MobileBridgePairingCode.swift and
    ios/ProgramaSpike/ProgramaSpike/PairingCode.swift — the format contract, and
    the only place the two targets can drift.
  2. Sources/SettingsView.swift — the Mac pairing UI.
  3. ios/ProgramaSpike/ProgramaSpike/{QRScannerView,PairConnectView,AppStore}.swift.
  4. The rest is fallout.

Known gap

The new iOS strings are bare English literals. The iOS target has no String
Catalog and its existing convention is literals, so this matches what is there —
but it does not meet the repo-wide localization rule the Mac side follows. Adding
that infrastructure is worth its own change before Japanese testers see this.

Test Plan

  • ./scripts/reload.sh --tag ios-pair-qr → exit 0 (verified)
  • iOS xcodebuild ... -destination 'generic/platform=iOS'** BUILD SUCCEEDED ** (verified)
  • /usr/libexec/PlistBuddy -c "Print :NSCameraUsageDescription" ios/ProgramaSpike/ProgramaSpike/Info.plist prints the description (verified)
  • On device: scan the Mac's QR, confirm it pairs and the countdown ticks down
  • On device: deny camera permission, confirm the message appears and the paste fallback still works

arzafran added 2 commits July 30, 2026 00:02
Setting up the phone meant copying two long opaque strings from Mac
Settings into two fields on the phone, with no QR code and a five minute
window that gave no hint it was running out. That was the biggest thing
standing between a new tester and a working companion.

Now the Mac shows a QR code and one combined link, with a live countdown,
and the phone can scan it with the camera or take a single paste. The old
two-field path is still there behind a disclosure, so nothing breaks if
the camera is unavailable or a tester prefers pasting.

Also adds a README with the setup steps, including the two easy things to
get wrong: the Mac toggle is off by default, and both devices have to be
on the same iCloud account for background notifications.

The combined code carries a version marker that both sides check, so a
newer Mac cannot quietly hand an older phone a format it would misread.
The phone ships through TestFlight and will lag the Mac app, so that skew
is the normal case rather than an edge one.
@arzafran
arzafran merged commit 45dd3ba into main Jul 30, 2026
11 checks passed
@arzafran
arzafran deleted the feat/ios-pairing-one-scan branch July 30, 2026 03:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant