“Run With It” Project Outline
“Run With It” is a fun, modular SwiftUI watchOS 10 app that hooks into HealthKit’s outdoor workout sessions to give you
real-time heart-rate and distance feedback right on your wrist. We split the heavy lifting into two simple managers (
HeartRateManager for your BPM and WorkoutManager for distance), built three clean SwiftUI screens (SetupView,
RunningWorkoutView, SummaryView), and battled through Xcode’s target quirks, Info.plist permissions, and Simulator
oddities. The result? A solid blueprint for instant running insights on Apple Watch.
1. Core Managers (in code)
HeartRateManager
- Purpose: Starts an
.outdoorHKWorkoutSession, streams live heart-rate (and distance) viaHKLiveWorkoutBuilderDelegate. - Key methods:
requestAuthorization()– HealthKit read/write permissions for heart rate & workoutsstartWorkout()– configures & begins the workout sessionstopWorkout()– ends collection and saves the workout
- Published state:
@Published var heartRate: Double?@Published var distance: Double
WorkoutManager (legacy / optional)
- Initially handled manual Core Location distance TDD.
- Now superseded by HealthKit’s built-in distance in
HeartRateManager.
2. View Coordination
RunSessionCoordinator (suggested)
- A thin wrapper to unify:
startRun()→ callsstartWorkout()+startTracking()stopRun()→ callsstopWorkout()+stopTracking()
3. SwiftUI Screens
All views live in the single Watch App target under SwiftUI’s App lifecycle:
-
SetupView.swift
- Owns
@StatefortimeGoal,distanceGoal - Presents modal pickers (WheelPicker) for input
- Exposes
onStart: (time, distance) -> Voidcallback
- Owns
-
RunningWorkoutView.swift
- Displays one metric: countdown or distance
- Shows “BPM: XXX” or “BPM: -”
- Includes a Cancel Workout button that ends the session
-
SummaryView.swift
- Shows final time or distance
- Offers a New Run button to reset
-
ContentView.swift
- Hosts a
TabViewwith three pages: - Tag 0 →
SetupView - Tag 1 →
RunningWorkoutView - Tag 2 →
SummaryView - Holds shared
@StateObjectand@State(goals, timer,pageIndex) - Calls
heartRateManager.requestAuthorization()inonAppear
- Hosts a
4. Gotchas & Configuration
- Single Watch App target only (no separate Extension).
- Info.plist keys (Watch App bundle):
NSHealthShareUsageDescriptionNSHealthUpdateUsageDescription
- Simulator quirks:
- Heart-rate streams take ~5–10 s to appear
- No true Watch→Phone Health sync
- Use GPX injection (Debug → Location) for distance testing
- Hardware testing is essential for reliable end-to-end validation.
5. Next Steps
- Implement halfway & finish haptic/audio cues
- Visualize heart-rate zones with color bands
- Add
RunSessionCoordinatorfor cleaner view logic - Add PreviewProviders to each view for rapid UI iteration