diff --git a/README.md b/README.md index 74ade31..a02be70 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,36 @@ A sample iOS app demonstrating the LocalData package capabilities for secure, ty This app provides interactive demos for all LocalData storage options: -| Tab | Demo | Storage Domain | -|-----|------|----------------| -| **Defaults** | Save/load/remove values | UserDefaults | +| Screen | Demo | Storage Domain | +|--------|------|----------------| +| **UserDefaults** | Save/load/remove values | UserDefaults | | **Keychain** | Secure credentials with biometrics | Keychain | -| **Files** | User profiles with Codable models | File System | -| **Encrypted** | Encrypted logs (AES or ChaCha20) | Encrypted File System | -| **Sync** | Platform availability & sync policies | Multiple | +| **File Storage** | User profiles with Codable models | File System | +| **Encrypted Storage** | Encrypted logs (AES or ChaCha20) | Encrypted File System | +| **Platform Sync Lab** | Platform availability & sync policies | Multiple | The project also includes a watchOS companion app target for watch-specific demos. +The watch app displays the synced user profile and the syncable setting from the Platform Sync Lab. +On iPhone launch and when the watch becomes available, the app re-sends any syncable keys so the watch updates without manual re-entry. +The watch app also requests a sync on launch when the iPhone is reachable. + +## Watch Sync Handshake + +This sample uses a launch-order-safe handshake so either app can start first: + +1. **Watch app launches** → sends a `request_sync` message (or queues it if the iPhone is unreachable). +2. **iOS app receives the request** → replies with a snapshot of current syncable keys and updates `applicationContext`. +3. **Watch app applies the snapshot** → UI updates immediately. + +This avoids requiring users to remember which app to open first. + +### Where the Logic Lives + +- iOS WCSession + handshake: `SecureStorageSample/SecureStorageSample/Services/WatchConnectivityService.swift` +- Bootstrap on launch: `SecureStorageSample/SecureStorageSample/SecureStorageSampleApp.swift` +- Sync policy UI lab: `SecureStorageSample/SecureStorageSample/Views/PlatformSyncDemo.swift` +- Watch WCSession + request: `SecureStorageSample/SecureStorageSample Watch App/Services/WatchConnectivityService.swift` +- Watch payload handlers: `SecureStorageSample/SecureStorageSample Watch App/Services/Handlers/` ## Requirements diff --git a/SecureStorageSample Watch App/README.md b/SecureStorageSample Watch App/README.md index 387b6a6..c1fb902 100644 --- a/SecureStorageSample Watch App/README.md +++ b/SecureStorageSample Watch App/README.md @@ -4,7 +4,7 @@ A watchOS companion app demonstrating data synchronization with the iOS app usin ## Overview -This watch app receives `UserProfile` data synced from the paired iPhone via `WCSession.updateApplicationContext`. It does **not** use LocalData directly for storage—instead, it displays synced data in memory. +This watch app receives `UserProfile` data and the syncable setting from the paired iPhone via WatchConnectivity. It does **not** use LocalData directly for storage—instead, it displays synced data in memory. ## Architecture @@ -12,6 +12,8 @@ This watch app receives `UserProfile` data synced from the paired iPhone via `WC SecureStorageSample Watch App/ ├── ContentView.swift # Displays synced profile data ├── SecureStorageSampleApp.swift +├── Design/ +│ └── WatchDesignConstants.swift ├── Protocols/ │ └── WatchDataHandling.swift # Protocol for payload handlers ├── State/ @@ -20,15 +22,25 @@ SecureStorageSample Watch App/ ├── WatchConnectivityService.swift └── Handlers/ └── UserProfileWatchHandler.swift + └── SyncableSettingWatchHandler.swift ``` ## Data Flow -1. **iOS app** calls `SyncHelper` when storing data with `syncPolicy: .automaticSmall` or `.manual` -2. `SyncHelper` sends data via `WCSession.updateApplicationContext` +1. **Watch app** requests a sync when it launches or becomes reachable +2. **iOS app** replies with a snapshot of syncable keys and updates `applicationContext` 3. **Watch app** receives context in `WatchConnectivityService` 4. The service dispatches each payload key to its registered `WatchDataHandling` handler -5. `UserProfileWatchHandler` decodes the profile and updates `WatchProfileStore` +5. Handlers decode values and update `WatchProfileStore` + +## Launch-Order-Safe Sync + +The watch app handles both cases: + +- If the iPhone is reachable, it sends a `request_sync` message and applies the reply payload. +- If the iPhone is not reachable, it queues a request with `transferUserInfo` and shows a badge. + +This ensures users do not need to launch the apps in a specific order. ## Adding New Sync Payloads