axiom-core-location-diag
37
总安装量
37
周安装量
#5559
全站排名
安装命令
npx skills add https://github.com/charleswiltgen/axiom --skill axiom-core-location-diag
Agent 安装分布
claude-code
28
opencode
25
codex
22
cursor
21
gemini-cli
19
antigravity
19
Skill 文档
Core Location Diagnostics
Symptom-based troubleshooting for Core Location issues.
When to Use
- Location updates never arrive
- Background location stops working
- Authorization always denied
- Location accuracy unexpectedly poor
- Geofence events not triggering
- Location icon won’t go away
Related Skills
axiom-core-locationâ Implementation patterns, decision treesaxiom-core-location-refâ API reference, code examplesaxiom-energy-diagâ Battery drain from location
Symptom 1: Location Updates Never Arrive
Quick Checks
// 1. Check authorization
let status = CLLocationManager().authorizationStatus
print("Authorization: \(status.rawValue)")
// 0=notDetermined, 1=restricted, 2=denied, 3=authorizedAlways, 4=authorizedWhenInUse
// 2. Check if location services enabled system-wide
print("Services enabled: \(CLLocationManager.locationServicesEnabled())")
// 3. Check accuracy authorization
let accuracy = CLLocationManager().accuracyAuthorization
print("Accuracy: \(accuracy == .fullAccuracy ? "full" : "reduced")")
Decision Tree
Q1: What does authorizationStatus return?
ââ .notDetermined â Authorization never requested
â Fix: Add CLServiceSession(authorization: .whenInUse) or requestWhenInUseAuthorization()
â
ââ .denied â User denied access
â Fix: Show UI explaining why location needed, link to Settings
â
ââ .restricted â Parental controls block access
â Fix: Inform user, offer manual location input
â
ââ .authorizedWhenInUse / .authorizedAlways â Check next
Q2: Is locationServicesEnabled() returning true?
ââ NO â Location services disabled system-wide
â Fix: Show UI prompting user to enable in Settings â Privacy â Location Services
â
ââ YES â Check next
Q3: Are you iterating the AsyncSequence?
ââ NO â Updates only arrive when you await
â Fix: Task { for try await update in CLLocationUpdate.liveUpdates() { ... } }
â
ââ YES â Check next
Q4: Is the Task cancelled or broken?
ââ YES â Task cancelled before updates arrived
â Fix: Ensure Task lives long enough (store in property, not local)
â
ââ NO â Check next
Q5: Is location available? (iOS 17+)
ââ Check update.locationUnavailable
â If true: Device cannot determine location (indoors, airplane mode, no GPS)
â Fix: Wait or inform user to move to better location
â
ââ Check update.authorizationDenied / update.authorizationDeniedGlobally
If true: Handle denial gracefully
Info.plist Checklist
<!-- Required for any location access -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>Your clear explanation here</string>
<!-- Required for Always authorization -->
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Your clear explanation here</string>
Missing these keys = silent failure with no prompt.
Symptom 2: Background Location Not Working
Quick Checks
- Background mode capability: Xcode â Signing & Capabilities â Background Modes â Location updates
- Info.plist: Should have
UIBackgroundModeswithlocationvalue - CLBackgroundActivitySession: Must be created AND held
Decision Tree
Q1: Is "Location updates" checked in Background Modes?
ââ NO â Background location silently disabled
â Fix: Xcode â Signing & Capabilities â Background Modes â Location updates
â
ââ YES â Check next
Q2: Are you holding CLBackgroundActivitySession?
ââ NO / Using local variable â Session deallocates, background stops
â Fix: Store in property: var backgroundSession: CLBackgroundActivitySession?
â
ââ YES â Check next
Q3: Was session started from foreground?
ââ NO â Cannot start new session from background
â Fix: Create CLBackgroundActivitySession while app in foreground
â
ââ YES â Check next
Q4: Is app being terminated and not recovering?
ââ YES â Not recreating session on relaunch
â Fix: In didFinishLaunchingWithOptions:
â if wasTrackingLocation {
â backgroundSession = CLBackgroundActivitySession()
â startLocationUpdates()
â }
â
ââ NO â Check authorization level
Q5: What is authorization level?
ââ .authorizedWhenInUse â This is fine with CLBackgroundActivitySession
â The blue indicator allows background access
â
ââ .authorizedAlways â Should work, check session lifecycle
â
ââ .denied â No background access possible
Common Mistakes
// â WRONG: Local variable deallocates immediately
func startTracking() {
let session = CLBackgroundActivitySession() // Dies at end of function!
startLocationUpdates()
}
// â
RIGHT: Property keeps session alive
var backgroundSession: CLBackgroundActivitySession?
func startTracking() {
backgroundSession = CLBackgroundActivitySession()
startLocationUpdates()
}
Symptom 3: Authorization Always Denied
Decision Tree
Q1: Is this a fresh install or returning user?
ââ FRESH INSTALL with immediate denial â Check Info.plist strings
â Missing/empty NSLocationWhenInUseUsageDescription = automatic denial
â
ââ RETURNING USER â Check previous denial
Q2: Did user previously deny?
ââ YES â User must manually re-enable in Settings
â Fix: Show UI explaining value, with button to open Settings:
â UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!)
â
ââ NO â Check next
Q3: Are you requesting authorization at wrong time?
ââ Requesting when app not "in use" â insufficientlyInUse
â Check: update.insufficientlyInUse or diagnostic.insufficientlyInUse
â Fix: Only request authorization from foreground, during user interaction
â
ââ NO â Check next
Q4: Is device in restricted mode?
ââ YES â .restricted status (parental controls, MDM)
â Fix: Cannot override. Offer manual location input.
â
ââ NO â Check Info.plist again
Q5: Are Info.plist strings compelling?
ââ Generic string â Users more likely to deny
â Bad: "This app needs your location"
â Good: "Your location helps us show restaurants within walking distance"
â
ââ Review: Look at string from user's perspective
Info.plist String Best Practices
<!-- â BAD: Vague, no value proposition -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>We need your location.</string>
<!-- â
GOOD: Specific benefit to user -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>Your location helps show restaurants, coffee shops, and attractions within walking distance.</string>
<!-- â BAD: No explanation for Always -->
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>We need your location always.</string>
<!-- â
GOOD: Explains background benefit -->
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Enable background location to receive reminders when you arrive at saved places, even when the app is closed.</string>
Symptom 4: Location Accuracy Unexpectedly Poor
Quick Checks
// 1. Check accuracy authorization
let accuracy = CLLocationManager().accuracyAuthorization
print("Accuracy auth: \(accuracy == .fullAccuracy ? "full" : "reduced")")
// 2. Check update's accuracy flag (iOS 17+)
for try await update in CLLocationUpdate.liveUpdates() {
if update.accuracyLimited {
print("Accuracy limited - updates every 15-20 min")
}
if let location = update.location {
print("Horizontal accuracy: \(location.horizontalAccuracy)m")
}
}
Decision Tree
Q1: What is accuracyAuthorization?
ââ .reducedAccuracy â User chose approximate location
â Options:
â 1. Accept reduced accuracy (weather, city-level features)
â 2. Request temporary full accuracy:
â CLServiceSession(authorization: .whenInUse, fullAccuracyPurposeKey: "Navigation")
â 3. Explain value and link to Settings
â
ââ .fullAccuracy â Check environment and configuration
Q2: What is horizontalAccuracy on locations?
ââ > 100m â Likely using WiFi/cell only (no GPS)
â Causes: Indoors, airplane mode, dense urban canyon
â Fix: User needs to move to better location, or wait for GPS lock
â
ââ 10-100m â Normal for most use cases
â If need better: Use .automotiveNavigation or .otherNavigation config
â
ââ < 10m â Good GPS accuracy
Note: .automotiveNavigation can achieve ~5m
Q3: What LiveConfiguration are you using?
ââ .default or none â System manages, may prioritize battery
â If need more accuracy: Use .fitness, .otherNavigation, or .automotiveNavigation
â
ââ .fitness â Good for pedestrian activities
â
ââ .automotiveNavigation â Highest accuracy, axiom-highest battery
Only use for actual navigation
Q4: Is the location stale?
ââ Check location.timestamp
â If old: Device hasn't moved, or updates paused (isStationary)
â
ââ If timestamp recent but accuracy poor: Environmental issue
Requesting Temporary Full Accuracy (iOS 18+)
// Requires Info.plist entry:
// NSLocationTemporaryUsageDescriptionDictionary
// NavigationPurpose: "Precise location enables turn-by-turn directions"
let session = CLServiceSession(
authorization: .whenInUse,
fullAccuracyPurposeKey: "NavigationPurpose"
)
Symptom 5: Geofence Events Not Triggering
Quick Checks
let monitor = await CLMonitor("MyMonitor")
// 1. Check condition count (max 20)
let count = await monitor.identifiers.count
print("Conditions: \(count)/20")
// 2. Check specific condition
if let record = await monitor.record(for: "MyGeofence") {
let lastEvent = record.lastEvent
print("State: \(lastEvent.state)")
print("Date: \(lastEvent.date)")
if let geo = record.condition as? CLMonitor.CircularGeographicCondition {
print("Center: \(geo.center)")
print("Radius: \(geo.radius)m")
}
}
Decision Tree
Q1: How many conditions are monitored?
ââ 20 â At the limit, new conditions ignored
â Fix: Prioritize important conditions, swap dynamically based on user location
â Check: lastEvent.conditionLimitExceeded
â
ââ < 20 â Check next
Q2: What is the radius?
ââ < 100m â Unreliable, may not trigger
â Fix: Use minimum 100m radius for reliable detection
â
ââ >= 100m â Check next
Q3: Is the app awaiting monitor.events?
ââ NO â Events not processed, lastEvent not updated
â Fix: Always have a Task awaiting:
â for try await event in monitor.events { ... }
â
ââ YES â Check next
Q4: Was monitor reinitialized on app launch?
ââ NO â Monitor conditions lost after termination
â Fix: Recreate monitor with same name in didFinishLaunchingWithOptions
â
ââ YES â Check next
Q5: What does lastEvent show?
ââ state: .unknown â System hasn't determined state yet
â Wait for determination, or check if monitoring is working
â
ââ state: .satisfied â Inside region, waiting for exit
â
ââ state: .unsatisfied â Outside region, waiting for entry
â
ââ Check lastEvent.date â When was last update?
If very old: May not be monitoring correctly
Q6: Is accuracyLimited preventing monitoring?
ââ Check: lastEvent.accuracyLimited
â If true: Reduced accuracy prevents geofencing
â Fix: Request full accuracy or accept limitation
â
ââ NO â Check environment (device must have location access)
Common Mistakes
// â WRONG: Not awaiting events
let monitor = await CLMonitor("Test")
await monitor.add(condition, identifier: "Place")
// Nothing happens - no Task awaiting events!
// â
RIGHT: Always await events
let monitor = await CLMonitor("Test")
await monitor.add(condition, identifier: "Place")
Task {
for try await event in monitor.events {
switch event.state {
case .satisfied: handleEntry(event.identifier)
case .unsatisfied: handleExit(event.identifier)
case .unknown: break
@unknown default: break
}
}
}
// â WRONG: Creating multiple monitors with same name
let monitor1 = await CLMonitor("App") // OK
let monitor2 = await CLMonitor("App") // UNDEFINED BEHAVIOR
// â
RIGHT: One monitor instance per name
class LocationService {
private var monitor: CLMonitor?
func setup() async {
monitor = await CLMonitor("App")
}
}
Symptom 6: Location Icon Won’t Go Away
Quick Checks
The location arrow appears when:
- App actively receiving location updates
- CLMonitor is monitoring conditions
- Background activity session active
Decision Tree
Q1: Is your app still iterating liveUpdates?
ââ YES â Updates continue until you break/cancel
â Fix: Cancel the Task or break from loop:
â locationTask?.cancel()
â
ââ NO â Check next
Q2: Is CLBackgroundActivitySession still held?
ââ YES â Session keeps location access active
â Fix: Invalidate when done:
â backgroundSession?.invalidate()
â backgroundSession = nil
â
ââ NO â Check next
Q3: Is CLMonitor still monitoring conditions?
ââ YES â CLMonitor uses location for geofencing
â Note: This is expected behavior - icon shows monitoring active
â Fix: If truly done, remove all conditions:
â for id in await monitor.identifiers {
â await monitor.remove(id)
â }
â
ââ NO â Check next
Q4: Is legacy CLLocationManager still running?
ââ Check: manager.stopUpdatingLocation() called?
â Check: manager.stopMonitoring(for: region) for all regions?
â Fix: Ensure all legacy APIs stopped
â
ââ NO â Check other location-using frameworks
Q5: Other frameworks using location?
ââ MapKit with showsUserLocation = true â Shows location
â Fix: mapView.showsUserLocation = false when not needed
â
ââ Core Motion with location â Shows location
â
ââ Check all location-using code
Force Stop All Location
// Stop modern APIs
locationTask?.cancel()
backgroundSession?.invalidate()
backgroundSession = nil
// Remove all CLMonitor conditions
for id in await monitor.identifiers {
await monitor.remove(id)
}
// Stop legacy APIs
manager.stopUpdatingLocation()
manager.stopMonitoringSignificantLocationChanges()
manager.stopMonitoringVisits()
for region in manager.monitoredRegions {
manager.stopMonitoring(for: region)
}
Console Debugging
Filter Location Logs
# View locationd logs
log stream --predicate 'subsystem == "com.apple.locationd"' --level debug
# View your app's location-related logs
log stream --predicate 'subsystem == "com.apple.CoreLocation"' --level debug
# Filter for specific process
log stream --predicate 'process == "YourAppName" AND subsystem == "com.apple.CoreLocation"'
Common Log Messages
| Log Message | Meaning |
|---|---|
Client is not authorized |
Authorization denied or not requested |
Location services disabled |
System-wide toggle off |
Accuracy authorization is reduced |
User chose approximate location |
Condition limit exceeded |
At 20-condition maximum |
Background location access denied |
Missing background capability or session |
Resources
WWDC: 2023-10180, 2023-10147, 2024-10212
Docs: /corelocation, /corelocation/clmonitor, /corelocation/cllocationupdate
Skills: axiom-core-location, axiom-core-location-ref, axiom-energy-diag