Watch: share with the complication through a Keychain group, not an App Group

Automatic signing with an App Store Connect API key registers bundle IDs and
profiles but cannot create or assign App Groups, so the archive failed. A
keychain-access-groups entry needs no portal setup. The demo flag and last
summary move into the same group; tests cover the round trip and the
migration of a pre-complication token.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
gibandClaude Opus 5.5 committed 2026-11-01 11:15:31 -05:00
1 parent 67992dbf43
commit 27469dbc77
11 files changed
+132 -49

No files matched your search

+7 -5
View File
@@ -66,10 +66,12 @@ there is one (`wristcode://thread/<hostId>/<threadId>`). WidgetKit refreshes it
the app reloads it sooner when its feed counts change, when a push arrives in the foreground, and
after a notification action.
The app and the extension share the App Group `group.org.gbrown.wristcode`. The device token and
gateway URL live in that group's Keychain access group, and the demo flag and last summary in its
defaults. Builds before the complication kept the token in the app's own Keychain group;
`DeviceStore.migrateToSharedGroup()` moves it on launch, so a paired watch stays paired.
The app and the extension share the Keychain access group `<team>.org.gbrown.wristcode.shared`, which
holds the device token, gateway URL, demo flag and last summary. It is not an App Group because
automatic signing with an App Store Connect API key can register bundle IDs and profiles but cannot
create or assign App Groups; a Keychain group needs no portal setup. Builds before the complication
kept the token in the app's own Keychain group; `DeviceStore.migrateToSharedGroup()` moves it on
launch, so a paired watch stays paired.
To add it: long-press the watch face, Edit, swipe to Complications, pick a slot, then WristCode.
@@ -83,7 +85,7 @@ To add it: long-press the watch face, Edit, swipe to Complications, pick a slot,
| `API/Models.swift` | Codable mirror of the contract |
| `API/Route.swift` | Screens the app can open, and their `wristcode://` URLs |
| `Auth/DeviceStore.swift` | Device token and gateway URL in the shared Keychain group |
| `Shared/SharedState.swift` | Demo flag and last summary in the App Group, for the complication |
| `Shared/SharedState.swift` | Demo flag and last summary in the shared Keychain group, for the complication |
| `Demo/DemoGateway.swift` | In-memory gateway with fixtures |
| `Views/` | Pair, Feed, Thread, New thread, and the mock B theme |
| `Notifications/NotificationHandler.swift` | Categories `approval`, `finished`, `failed`, `input`, `host` and their actions |