A watch that navigates nothing still needs a navigation session
The watch does not measure the route. The phone does that, and the glance tells the wrist what it found. Yet the watch app starts a continuous location session of its own as soon as it is open and the phone is guiding a walk or a drive. The reason is not location at all. It is the taps.
watchOS has haptics made for turns: navigationLeftTurn, navigationRightTurn, navigationGenericManeuver. Apple's page for them is short and strict: you can only use this haptic type when your app is running a continuous background location session. The same session is what keeps the watch app alive with the wrist down and brings it back on a wrist raise. So WatchNavigationSession exists, in its own header's words, for exactly that, and "the phone stays the navigator".
Its settings say how little it asks for. The activity type is .fitness on a walk and .automotiveNavigation on a drive. The accuracy is kCLLocationAccuracyNearestTenMeters with a 10 m distance filter, because the watch's own fix only draws the dot on its little map, and a coarse one spares the battery. Background updates are allowed only while the session runs, and the watch's Info.plist declares the location background mode that makes them possible.
When In Use on the wrist too
Pathfinder asks for location When In Use, never Always, and the watch keeps that rule (architecture invariant 5). It has a price: watchOS lets such a session start only with the app in front. WatchModel.updateSession encodes it in one condition: start when the phone guides, the trip has not arrived, the scene is active, and no session runs yet; stop when the guidance ends or arrives. A session that has started keeps running with the wrist down. One that never started cannot be started from the background, and that is the honest limit the architecture writes down: the watch taps while its session runs, started with its app in front.
The first time, the session asks for permission and remembers what it was about to do (pending), so a yes starts it without another tap. A no is said on the controls page in plain words: "Allow location for Pathfinder in the watch's Settings to tap the turns."
The cue: numbered so it taps once
The phone decides when a tap is due and the watch decides whether to play it. On every guidance moment that deserves a tap (the prepare and imminent stages of a turn, the arrival, going off route, a camera) the phone bumps a serial and puts a Cue with that serial, its kind and the time into the glance. The early stage gets no tap: it is too far ahead to act on.
The watch's side is tapIfDue, and every line answers a way it could go wrong:
- Once per serial. A cue is played only if its serial is higher than the last one handled. That matters more than it looks: the phone keeps its last cue and puts it in every glance it publishes until the next one, so the same cue reaches the watch again and again. A relaunch does not reset it either, because the last serial is kept in
UserDefaults. - Consumed before it is judged. The serial is recorded first, then freshness is checked. A cue older than
Cue.freshFor = 20seconds is history: a watch that wakes to an old context does not buzz for a corner already passed, and that cue will never buzz later either. - Numbers that never go backwards. The phone seeds its serial from the clock, so a relaunched phone starts above any number the watch has already handled. That holds as long as cues come slower than one a second, which turns do.
- One tapper per turn. The watch plays the cue only if its session runs, the phone app is on screen, or the trip is a drive. On a walk with the phone app in the background and no watch session, the phone's notification taps the wrist instead (track 5 has both halves of that rule).
WatchHaptics then picks the feel: the navigation haptics while the session runs, the plain .notification tap without one, and .success for arriving and .retry for going off route either way.
Three pages, and a map that must not be touched
The watch app is a vertical page stack. While a trip is guided: the turn ahead, then the way on a map (only when the route's line came along, so never on a Kakao or Google trip), then the controls with Pippa, the voice and End Route. With nothing guided, the first page is Dad's saved places instead.
The map page taught the one watchOS lesson in this track that is about layout. On the watch simulator, a swipe on an interactive SwiftUI Map panned the map instead of paging, so the controls below it could not be reached (coop learning #735, fixed in fc2558d). The map is now Map(position:interactionModes: []), a glance rather than a map to work, and a swipe pages as it does everywhere else. Its dot is the watch's own fix while the session runs, and the phone's matched position otherwise. The learning records one honest gap: the swipe was proven on the simulator, and the Digital Crown on a device was not tested.