While working on the watch side of Soccer Mappr, I hit a permission bug that made no sense at first: every time I opened the app, the location permission prompt appeared again. I would tap "Allow", the session would work fine, and then the next launch would ask all over again as if I had never answered.

The setup looked correct. The watch app uses CLLocationManager so I had added NSLocationWhenInUseUsageDescription to the Watch target's Info.plist. That's where the code runs, so that's where the key belongs. Or so I thought. Checking the authorization status confirmed the weird part: it came back as .notDetermined on every new session, even right after the user had granted access.

It turns out that on watchOS, location authorization isn't owned by the watch at all. It's arbitrated by the paired iPhone. When you grant location access on the watch, the system needs to record that grant on the iPhone side and it can only do that if the iOS companion target declares the same usage description keys. Without them, the system has nowhere to persist the answer, so the grant silently evaporates and .notDetermined comes back on the next launch.

The fix was to add the same NSLocationWhenInUseUsageDescription key to the iOS companion target's Info.plist. Even though the companion app never directly calls CLLocationManager. Once the keys exist on both sides, the grant persists across sessions and the prompt shows up only once, as it should.

The counterintuitive lesson: the target that runs the location code is not necessarily the target that owns the permission. On watchOS, the iPhone is the source of truth, so the usage description keys have to live in both places.

Source: Apple Developer Forums: How to properly ask for location permissions in WatchOS 8