axiom-core-location-diag by charleswiltgen/axiom
npx skills add https://github.com/charleswiltgen/axiom --skill axiom-core-location-diag基于症状的 Core Location 问题排查指南。
axiom-core-location — 实现模式,决策树axiom-core-location-ref — API 参考,代码示例axiom-energy-diag — 定位导致的电池耗尽axiom-mapkit-diag — 针对地图特定位置显示问题(症状 7)// 1. 检查授权状态
let status = CLLocationManager().authorizationStatus
print("Authorization: \(status.rawValue)")
// 0=notDetermined, 1=restricted, 2=denied, 3=authorizedAlways, 4=authorizedWhenInUse
// 2. 检查系统级定位服务是否启用
print("Services enabled: \(CLLocationManager.locationServicesEnabled())")
// 3. 检查精度授权
let accuracy = CLLocationManager().accuracyAuthorization
print("Accuracy: \(accuracy == .fullAccuracy ? "full" : "reduced")")
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
Q1: authorizationStatus 返回什么?
├─ .notDetermined → 从未请求过授权
│ 修复:添加 CLServiceSession(authorization: .whenInUse) 或调用 requestWhenInUseAuthorization()
│
├─ .denied → 用户拒绝访问
│ 修复:显示 UI 解释为何需要位置,并提供跳转到设置的链接
│
├─ .restricted → 家长控制阻止访问
│ 修复:通知用户,提供手动位置输入选项
│
└─ .authorizedWhenInUse / .authorizedAlways → 检查下一项
Q2: locationServicesEnabled() 返回 true 吗?
├─ 否 → 系统级定位服务已禁用
│ 修复:显示 UI 提示用户在 设置 → 隐私 → 定位服务 中启用
│
└─ 是 → 检查下一项
Q3: 你在遍历 AsyncSequence 吗?
├─ 否 → 只有当你 await 时更新才会到达
│ 修复:Task { for try await update in CLLocationUpdate.liveUpdates() { ... } }
│
└─ 是 → 检查下一项
Q4: Task 被取消或中断了吗?
├─ 是 → Task 在更新到达前被取消
│ 修复:确保 Task 存活足够长时间(存储在属性中,而非局部变量)
│
└─ 否 → 检查下一项
Q5: 位置可用吗?(iOS 17+)
├─ 检查 update.locationUnavailable
│ 如果为 true:设备无法确定位置(室内、飞行模式、无 GPS)
│ 修复:等待或通知用户移动到更好的位置
│
└─ 检查 update.authorizationDenied / update.authorizationDeniedGlobally
如果为 true:优雅地处理拒绝
<!-- 任何位置访问都需要 -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>在此处填写清晰的解释</string>
<!-- 始终授权需要 -->
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>在此处填写清晰的解释</string>
缺少这些键 = 静默失败,无提示。
location 的 UIBackgroundModes 键Q1: Background Modes 中勾选了 "Location updates" 吗?
├─ 否 → 后台定位被静默禁用
│ 修复:Xcode → Signing & Capabilities → Background Modes → Location updates
│
└─ 是 → 检查下一项
Q2: 你持有 CLBackgroundActivitySession 吗?
├─ 否 / 使用局部变量 → Session 被释放,后台停止
│ 修复:存储在属性中:var backgroundSession: CLBackgroundActivitySession?
│
└─ 是 → 检查下一项
Q3: Session 是从前台启动的吗?
├─ 否 → 无法从后台启动新的 Session
│ 修复:在应用处于前台时创建 CLBackgroundActivitySession
│
└─ 是 → 检查下一项
Q4: 应用是否被终止且未恢复?
├─ 是 → 重新启动时未重新创建 Session
│ 修复:在 didFinishLaunchingWithOptions: 中:
│ if wasTrackingLocation {
│ backgroundSession = CLBackgroundActivitySession()
│ startLocationUpdates()
│ }
│
└─ 否 → 检查授权级别
Q5: 授权级别是什么?
├─ .authorizedWhenInUse → 配合 CLBackgroundActivitySession 可以使用
│ 蓝色指示器允许后台访问
│
├─ .authorizedAlways → 应该工作,检查 Session 生命周期
│
└─ .denied → 无法进行后台访问
// ❌ 错误:局部变量立即释放
func startTracking() {
let session = CLBackgroundActivitySession() // 函数结束时失效!
startLocationUpdates()
}
// ✅ 正确:属性保持 Session 存活
var backgroundSession: CLBackgroundActivitySession?
func startTracking() {
backgroundSession = CLBackgroundActivitySession()
startLocationUpdates()
}
Q1: 这是全新安装还是回头用户?
├─ 全新安装且立即被拒 → 检查 Info.plist 字符串
│ 缺少/空的 NSLocationWhenInUseUsageDescription = 自动拒绝
│
└─ 回头用户 → 检查之前的拒绝
Q2: 用户之前拒绝过吗?
├─ 是 → 用户必须手动在设置中重新启用
│ 修复:显示 UI 解释价值,并提供打开设置的按钮:
│ UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!)
│
└─ 否 → 检查下一项
Q3: 你在错误的时间请求授权吗?
├─ 在应用未"使用中"时请求 → insufficientlyInUse
│ 检查:update.insufficientlyInUse 或 diagnostic.insufficientlyInUse
│ 修复:仅在前台、用户交互期间请求授权
│
└─ 否 → 检查下一项
Q4: 设备处于受限模式吗?
├─ 是 → .restricted 状态(家长控制,MDM)
│ 修复:无法覆盖。提供手动位置输入选项。
│
└─ 否 → 再次检查 Info.plist
Q5: Info.plist 字符串有说服力吗?
├─ 通用字符串 → 用户更可能拒绝
│ 差:"此应用需要您的位置"
│ 好:"您的位置帮助我们显示步行距离内的餐厅"
│
└─ 审查:从用户角度审视字符串
<!-- ❌ 差:模糊,无价值主张 -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>我们需要您的位置。</string>
<!-- ✅ 好:对用户的具体好处 -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>您的位置有助于显示步行距离内的餐厅、咖啡店和景点。</string>
<!-- ❌ 差:未解释"始终"授权的原因 -->
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>我们始终需要您的位置。</string>
<!-- ✅ 好:解释后台好处 -->
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>启用后台定位,以便在您到达已保存地点时接收提醒,即使应用已关闭。</string>
// 1. 检查精度授权
let accuracy = CLLocationManager().accuracyAuthorization
print("Accuracy auth: \(accuracy == .fullAccuracy ? "full" : "reduced")")
// 2. 检查更新的精度标志(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")
}
}
Q1: accuracyAuthorization 是什么?
├─ .reducedAccuracy → 用户选择了近似位置
│ 选项:
│ 1. 接受降低的精度(天气、城市级功能)
│ 2. 请求临时完全精度:
│ CLServiceSession(authorization: .whenInUse, fullAccuracyPurposeKey: "Navigation")
│ 3. 解释价值并链接到设置
│
└─ .fullAccuracy → 检查环境和配置
Q2: 位置的 horizontalAccuracy 是多少?
├─ < 0(通常为 -1)→ 无效位置,请勿使用
│ 含义:系统无法确定精度(无有效定位)
│ 修复:过滤掉:guard location.horizontalAccuracy >= 0 else { continue }
│ 常见于:室内无 WiFi、飞行模式、冷启动后立即
│
├─ > 100m → 可能仅使用 WiFi/蜂窝网络(无 GPS)
│ 原因:室内、飞行模式、密集城市峡谷
│ 修复:用户需要移动到更好的位置,或等待 GPS 锁定
│
├─ 10-100m → 大多数用例的正常情况
│ 如果需要更好:使用 .automotiveNavigation 或 .otherNavigation 配置
│
└─ < 10m → 良好的 GPS 精度
注意:.automotiveNavigation 可实现约 5m
Q3: 你使用什么 LiveConfiguration?
├─ .default 或无 → 系统管理,可能优先考虑电池
│ 如果需要更高精度:使用 .fitness、.otherNavigation 或 .automotiveNavigation
│
├─ .fitness → 适合步行活动
│
└─ .automotiveNavigation → 最高精度,电池消耗最高
仅用于实际导航
Q4: 位置过时了吗?
├─ 检查 location.timestamp
│ 如果过时:设备未移动,或更新暂停(isStationary)
│
└─ 如果时间戳新但精度差:环境问题
// 需要 Info.plist 条目:
// NSLocationTemporaryUsageDescriptionDictionary
// NavigationPurpose: "精确位置可实现逐向导航"
let session = CLServiceSession(
authorization: .whenInUse,
fullAccuracyPurposeKey: "NavigationPurpose"
)
let monitor = await CLMonitor("MyMonitor")
// 1. 检查条件数量(最大 20)
let count = await monitor.identifiers.count
print("Conditions: \(count)/20")
// 2. 检查特定条件
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")
}
}
Q1: 监控了多少个条件?
├─ 20 → 达到限制,新条件被忽略
│ 修复:优先处理重要条件,根据用户位置动态交换
│ 检查:lastEvent.conditionLimitExceeded
│
└─ < 20 → 检查下一项
Q2: 半径是多少?
├─ < 100m → 不可靠,可能不触发
│ 修复:使用至少 100m 半径以确保可靠检测
│
└─ >= 100m → 检查下一项
Q3: 应用在 await monitor.events 吗?
├─ 否 → 事件未处理,lastEvent 未更新
│ 修复:始终有一个 Task 在等待:
│ for try await event in monitor.events { ... }
│
└─ 是 → 检查下一项
Q4: 应用启动时重新初始化 monitor 了吗?
├─ 否 → 终止后监控条件丢失
│ 修复:在 didFinishLaunchingWithOptions 中重新创建同名 monitor
│
└─ 是 → 检查下一项
Q5: lastEvent 显示什么?
├─ state: .unknown → 系统尚未确定状态
│ 等待确定,或检查监控是否正常工作
│
├─ state: .satisfied → 在区域内,等待退出
│
├─ state: .unsatisfied → 在区域外,等待进入
│
└─ 检查 lastEvent.date → 上次更新是什么时候?
如果非常旧:可能未正确监控
Q6: accuracyLimited 是否阻止了监控?
├─ 检查:lastEvent.accuracyLimited
│ 如果为 true:降低的精度阻止地理围栏
│ 修复:请求完全精度或接受限制
│
└─ 否 → 检查环境(设备必须具有位置访问权限)
// ❌ 错误:未等待事件
let monitor = await CLMonitor("Test")
await monitor.add(condition, identifier: "Place")
// 什么都没发生 - 没有 Task 在等待事件!
// ✅ 正确:始终等待事件
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
}
}
}
// ❌ 错误:创建多个同名 monitor
let monitor1 = await CLMonitor("App") // 正确
let monitor2 = await CLMonitor("App") // 未定义行为
// ✅ 正确:每个名称一个 monitor 实例
class LocationService {
private var monitor: CLMonitor?
func setup() async {
monitor = await CLMonitor("App")
}
}
位置箭头在以下情况出现:
Q1: 你的应用仍在遍历 liveUpdates 吗?
├─ 是 → 更新持续直到你中断/取消
│ 修复:取消 Task 或跳出循环:
│ locationTask?.cancel()
│
└─ 否 → 检查下一项
Q2: CLBackgroundActivitySession 仍被持有吗?
├─ 是 → Session 保持位置访问活动
│ 修复:完成后使其失效:
│ backgroundSession?.invalidate()
│ backgroundSession = nil
│
└─ 否 → 检查下一项
Q3: CLMonitor 仍在监控条件吗?
├─ 是 → CLMonitor 使用位置进行地理围栏
│ 注意:这是预期行为 - 图标显示监控活动
│ 修复:如果确实完成,移除所有条件:
│ for id in await monitor.identifiers {
│ await monitor.remove(id)
│ }
│
└─ 否 → 检查下一项
Q4: 传统的 CLLocationManager 仍在运行吗?
├─ 检查:是否调用了 manager.stopUpdatingLocation()?
│ 检查:是否为所有区域调用了 manager.stopMonitoring(for: region)?
│ 修复:确保所有传统 API 已停止
│
└─ 否 → 检查其他使用位置的框架
Q5: 其他框架在使用位置吗?
├─ MapKit 且 showsUserLocation = true → 显示位置
│ 修复:不需要时设置 mapView.showsUserLocation = false
│
├─ Core Motion 使用位置 → 显示位置
│
└─ 检查所有使用位置的代码
// 停止现代 API
locationTask?.cancel()
backgroundSession?.invalidate()
backgroundSession = nil
// 移除所有 CLMonitor 条件
for id in await monitor.identifiers {
await monitor.remove(id)
}
// 停止传统 API
manager.stopUpdatingLocation()
manager.stopMonitoringSignificantLocationChanges()
manager.stopMonitoringVisits()
for region in manager.monitoredRegions {
manager.stopMonitoring(for: region)
}
# 查看 locationd 日志
log stream --predicate 'subsystem == "com.apple.locationd"' --level debug
# 查看你应用的位置相关日志
log stream --predicate 'subsystem == "com.apple.CoreLocation"' --level debug
# 过滤特定进程
log stream --predicate 'process == "YourAppName" AND subsystem == "com.apple.CoreLocation"'
| 日志消息 | 含义 |
|---|---|
Client is not authorized | 授权被拒绝或未请求 |
Location services disabled | 系统级开关关闭 |
Accuracy authorization is reduced | 用户选择了近似位置 |
Condition limit exceeded | 达到 20 个条件上限 |
Background location access denied | 缺少后台能力或会话 |
WWDC : 2023-10180, 2023-10147, 2024-10212
文档 : /corelocation, /corelocation/clmonitor, /corelocation/cllocationupdate
技能 : axiom-core-location, axiom-core-location-ref, axiom-energy-diag
每周安装量
97
代码仓库
GitHub 星标
606
首次出现
Jan 21, 2026
安全审计
安装于
opencode83
codex77
gemini-cli76
cursor75
claude-code75
github-copilot73
Symptom-based troubleshooting for Core Location issues.
axiom-core-location — Implementation patterns, decision treesaxiom-core-location-ref — API reference, code examplesaxiom-energy-diag — Battery drain from locationaxiom-mapkit-diag — For map-specific location display issues (Symptom 7)// 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")")
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
<!-- 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.
UIBackgroundModes with location valueQ1: 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
// ❌ 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()
}
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
<!-- ❌ 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>
// 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")
}
}
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?
├─ < 0 (typically -1) → INVALID location, do not use
│ Meaning: System could not determine accuracy (no valid fix)
│ Fix: Filter out: guard location.horizontalAccuracy >= 0 else { continue }
│ Common when: Indoors with no WiFi, airplane mode, immediately after cold start
│
├─ > 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
// Requires Info.plist entry:
// NSLocationTemporaryUsageDescriptionDictionary
// NavigationPurpose: "Precise location enables turn-by-turn directions"
let session = CLServiceSession(
authorization: .whenInUse,
fullAccuracyPurposeKey: "NavigationPurpose"
)
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")
}
}
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)
// ❌ 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")
}
}
The location arrow appears when:
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
// 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)
}
# 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"'
| 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 |
WWDC : 2023-10180, 2023-10147, 2024-10212
Docs : /corelocation, /corelocation/clmonitor, /corelocation/cllocationupdate
Skills : axiom-core-location, axiom-core-location-ref, axiom-energy-diag
Weekly Installs
97
Repository
GitHub Stars
606
First Seen
Jan 21, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode83
codex77
gemini-cli76
cursor75
claude-code75
github-copilot73
OpenClaw 环境安全审计员:一键扫描密钥泄露,审计沙箱配置,保障AI技能运行安全
135 周安装
OpenViking 记忆插件指南:AI助手长期记忆管理与自动上下文注入
135 周安装
ByteRover CLI - 上下文工程平台,为AI编码智能体自动管理项目知识库
135 周安装
Symfony API Platform序列化指南:合约设计、安全防护与渐进式披露
135 周安装
PostgreSQL只读查询技能 - 安全连接AI助手执行数据库查询,支持SSL加密与权限控制
135 周安装
Next.js服务端与客户端组件选择指南:TypeScript最佳实践与性能优化
135 周安装