Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>

This commit is contained in:
Matt Bruce 2026-01-10 13:26:06 -06:00
parent 54d4561158
commit fcc266d795
2 changed files with 142 additions and 0 deletions

132
Agents.md
View File

@ -203,6 +203,138 @@ Button("Save") { state.save() }
- Avoid UIKit colors in SwiftUI code.
## watchOS Development (CRITICAL)
**Read this entire section before implementing any watch functionality.**
### Creating a Watch Target
When adding a watchOS target to an existing iOS app:
1. **File → New → Target → "Watch App for watchOS"**
2. Choose **"Watch App for Existing iOS App"** (NOT standalone)
3. Name it appropriately (e.g., `AppNameWatch`)
4. Xcode creates a folder like `AppNameWatch Watch App/`
### CRITICAL: Embedding the Watch App
⚠️ **THIS IS THE #1 CAUSE OF "WATCH APP NOT INSTALLED" ERRORS** ⚠️
The watch app MUST be embedded in the iOS app for deployment to real devices:
1. Select the **iOS target** in Xcode
2. Go to **Build Phases** tab
3. Verify there's an **"Embed Watch Content"** phase
4. **CRITICAL**: Ensure **"Code Sign On Copy"** is CHECKED ✓
If "Embed Watch Content" doesn't exist:
1. Click **"+"** → **"New Copy Files Phase"**
2. Rename to **"Embed Watch Content"**
3. Set **Destination** to **"Products Directory"**
4. Set **Subpath** to `$(CONTENTS_FOLDER_PATH)/Watch`
5. Add the watch app (e.g., `AppNameWatch Watch App.app`)
6. **CHECK "Code Sign On Copy"** ← This is critical!
Without proper embedding, the iOS app installs but the watch app does NOT install on the paired Apple Watch.
### Bundle Identifiers
Watch app bundle IDs MUST be prefixed with the iOS app's bundle ID:
```
iOS app: com.company.AppName
Watch app: com.company.AppName.watchkitapp ← MUST start with iOS bundle ID
```
Also verify `WKCompanionAppBundleIdentifier` in the watch target's build settings matches the iOS app's bundle ID exactly.
### Data Sync: WatchConnectivity (NOT App Groups)
**DO NOT use App Groups for iPhone ↔ Watch data sharing.**
App Groups:
- ❌ Do NOT work between iPhone and Apple Watch
- ❌ Different container paths on each device
- ❌ Will waste hours debugging why data isn't syncing
- ✅ Only work between an app and its extensions on the SAME device
**Use WatchConnectivity framework instead:**
```swift
// iOS side - WatchConnectivityService.swift
import WatchConnectivity
@MainActor
final class WatchConnectivityService: NSObject, WCSessionDelegate {
static let shared = WatchConnectivityService()
private override init() {
super.init()
if WCSession.isSupported() {
WCSession.default.delegate = self
WCSession.default.activate()
}
}
func syncData(_ data: [String: Any]) {
guard WCSession.default.activationState == .activated,
WCSession.default.isPaired,
WCSession.default.isWatchAppInstalled else { return }
try? WCSession.default.updateApplicationContext(data)
}
}
```
### WatchConnectivity Methods
| Method | Use Case |
|--------|----------|
| `updateApplicationContext` | Latest state that persists (use this for most syncs) |
| `sendMessage` | Immediate delivery when counterpart is reachable |
| `transferUserInfo` | Queued delivery, guaranteed but not immediate |
### watchOS Framework Limitations
These iOS frameworks are NOT available on watchOS:
- ❌ `CoreImage` - Generate QR codes on iOS, send image data to watch
- ❌ `UIKit` (mostly) - Use SwiftUI
- ❌ `AVFoundation` (limited)
### Simulator Limitations
WatchConnectivity on simulators is **unreliable**:
- `isWatchAppInstalled` often returns `false` even when running
- `isReachable` may be `false` even with both apps running
- `updateApplicationContext` may fail with "counterpart not installed"
**Workarounds for simulator testing:**
1. Add `#if targetEnvironment(simulator)` blocks with sample data
2. Test real sync functionality on physical devices only
### Debugging Watch Sync Issues
If `isWatchAppInstalled` returns `false`:
1. ✅ Check "Embed Watch Content" build phase exists
2. ✅ Check "Code Sign On Copy" is enabled
3. ✅ Verify bundle ID is prefixed correctly
4. ✅ Clean build folder (⇧⌘K) and rebuild
5. ✅ On iPhone, open Watch app → verify app appears under "Installed"
### NSObject Requirement
`WCSessionDelegate` is an Objective-C protocol, so conforming classes must inherit from `NSObject`:
```swift
final class WatchConnectivityService: NSObject, WCSessionDelegate {
// NSObject is required for WCSessionDelegate conformance
}
```
## SwiftData Instructions
If SwiftData is configured to use CloudKit:

View File

@ -177,6 +177,16 @@ BusinessCardTests/ # Unit tests
**watchOS Target:**
- WatchConnectivity (for receiving cards from iPhone)
- Bundle ID must be prefixed with iOS bundle ID (e.g., `com.mbrucedogs.BusinessCard.watchkitapp`)
### Watch App Embedding (CRITICAL)
The watch app must be embedded in the iOS app for deployment. In the iOS target's **Build Phases**:
1. **"Embed Watch Content"** phase must exist
2. **"Code Sign On Copy"** must be CHECKED ✓
Without this, the iOS app installs but the watch app does NOT install on the paired Apple Watch. See `Agents.md` for full troubleshooting guide.
### CloudKit Container