apple-corelocation
Original:🇺🇸 English
Translated
Reference skill for Apple's CoreLocation framework in Swift/SwiftUI. Use this skill whenever the user works with location services, GPS, geofencing, beacon ranging, geocoding, compass headings, or any CLLocationManager-related code on iOS, macOS, watchOS, or visionOS. Trigger on mentions of: CoreLocation, CLLocationManager, CLLocation, location permissions, geofencing, CLMonitor, iBeacon, CLGeocoder, reverse geocoding, background location updates, "When In Use" / "Always" authorization, CLLocationUpdate, live updates, significant location changes, or any location-related Info.plist keys like NSLocationWhenInUseUsageDescription.
1installs
Sourceios-agent/iosagent.dev
Added on
NPX Install
npx skill4agent add ios-agent/iosagent.dev apple-corelocationTags
Translated version includes tags in frontmatterSKILL.md Content
View Translation Comparison →Apple CoreLocation Skill
Use this skill to write correct, modern CoreLocation code. CoreLocation provides
services for geographic location, altitude, orientation, and proximity to iBeacons.
It uses Wi-Fi, GPS, Bluetooth, magnetometer, barometer, and cellular hardware.
When to Read Reference Files
This SKILL.md contains the essential patterns and quick-reference API surface.
For deeper implementation details, read the appropriate reference file:
| Topic | Reference File | When to Read |
|---|---|---|
| Live Updates & async/await patterns | | SwiftUI apps, async location streams, background activity sessions |
| Authorization & Permissions | | Permission flows, Info.plist keys, authorization status handling |
| Region Monitoring & CLMonitor | | Geofencing, condition monitoring, circular regions |
| Geocoding | | Address ↔ coordinate conversion, reverse geocoding, CLPlacemark |
| iBeacon & Compass | | Beacon ranging, heading updates, magnetometer |
| Background Location | | Background updates, CLBackgroundActivitySession, power optimization |
| CLLocationManager API | | Full property/method reference for CLLocationManager |
Modern CoreLocation (iOS 17+): Prefer Async/Await
Since iOS 17, CoreLocation supports Swift concurrency. Prefer the modern async API
over the legacy delegate-based approach for new projects.
Getting Live Location Updates (Recommended Pattern)
swift
import CoreLocation
let updates = CLLocationUpdate.liveUpdates()
for try await update in updates {
if let location = update.location {
// Process location
print("Lat: \(location.coordinate.latitude), Lon: \(location.coordinate.longitude)")
}
if update.authorizationDenied {
// Handle denied authorization
}
if update.authorizationRequestInProgress {
// System is showing the authorization dialog
}
}The system automatically prompts for authorization when iteration begins if
status is . No explicit call
is needed with this pattern, but you may still call it for controlled timing.
.notDeterminedrequestWhenInUseAuthorization()Live Updates with Accuracy Configuration
swift
// High accuracy (GPS, more power)
let updates = CLLocationUpdate.liveUpdates(.default)
// Power-efficient options
let updates = CLLocationUpdate.liveUpdates(.automotiveNavigation)
let updates = CLLocationUpdate.liveUpdates(.otherNavigation)
let updates = CLLocationUpdate.liveUpdates(.fitness)
let updates = CLLocationUpdate.liveUpdates(.airborne)CLLocationUpdate Properties
- — The location, or nil if unavailable
location: CLLocation? - — Whether the device is stationary
isStationary: Bool - — Authorization was denied
authorizationDenied: Bool - — Location services disabled system-wide
authorizationDeniedGlobally: Bool - — Auth dialog is being shown
authorizationRequestInProgress: Bool - — App lacks sufficient "in use" state
insufficientlyInUse: Bool - — Location data temporarily unavailable
locationUnavailable: Bool - — Accuracy authorization is reduced
accuracyLimited: Bool
SwiftUI Integration Pattern
swift
@MainActor
class LocationsHandler: ObservableObject {
static let shared = LocationsHandler()
private let manager: CLLocationManager
private var background: CLBackgroundActivitySession?
@Published var lastLocation = CLLocation()
@Published var isStationary = false
@Published var updatesStarted: Bool = UserDefaults.standard.bool(forKey: "liveUpdatesStarted") {
didSet { UserDefaults.standard.set(updatesStarted, forKey: "liveUpdatesStarted") }
}
private init() {
self.manager = CLLocationManager()
}
func startLocationUpdates() {
if self.manager.authorizationStatus == .notDetermined {
self.manager.requestWhenInUseAuthorization()
}
Task {
do {
self.updatesStarted = true
let updates = CLLocationUpdate.liveUpdates()
for try await update in updates {
if !self.updatesStarted { break }
if let loc = update.location {
self.lastLocation = loc
self.isStationary = update.isStationary
}
}
} catch {
print("Could not start location updates")
}
}
}
func stopLocationUpdates() {
self.updatesStarted = false
}
}Authorization Quick Reference
Info.plist Keys (Required)
| Key | When to Use |
|---|---|
| App uses location while in foreground |
| App needs location in background too |
| Request reduced accuracy by default |
Authorization Status Values (CLAuthorizationStatus
)
CLAuthorizationStatus| Value | Meaning |
|---|---|
| User hasn't been asked yet |
| App cannot use location (e.g., parental controls) |
| User explicitly denied |
| App can use location while in foreground |
| App can use location at any time |
Requesting Authorization
swift
let manager = CLLocationManager()
// For foreground-only access
manager.requestWhenInUseAuthorization()
// For background access (after getting "When In Use" first)
manager.requestAlwaysAuthorization()
// For temporary full accuracy (when user granted reduced accuracy)
manager.requestTemporaryFullAccuracyAuthorization(withPurposeKey: "MyPurposeKey")Condition Monitoring with CLMonitor (iOS 17+)
swift
let monitor = await CLMonitor("myMonitor")
// Add a circular geographic condition
await monitor.add(
CLMonitor.CircularGeographicCondition(center: coordinate, radius: 200),
identifier: "coffee-shop"
)
// Observe events
for try await event in await monitor.events {
switch event.state {
case .satisfied:
print("Entered region: \(event.identifier)")
case .unsatisfied:
print("Exited region: \(event.identifier)")
default:
break
}
}Geocoding Quick Reference
swift
let geocoder = CLGeocoder()
// Reverse geocode: coordinate → address
geocoder.reverseGeocodeLocation(location) { placemarks, error in
if let placemark = placemarks?.first {
print(placemark.locality ?? "Unknown city")
}
}
// Forward geocode: address → coordinate
geocoder.geocodeAddressString("1 Apple Park Way, Cupertino") { placemarks, error in
if let location = placemarks?.first?.location {
print(location.coordinate)
}
}CLLocation Key Properties
| Property | Type | Description |
|---|---|---|
| | Latitude and longitude (WGS 84) |
| | Meters above sea level |
| | Accuracy in meters (negative = invalid) |
| | Altitude accuracy in meters |
| | Meters per second |
| | Degrees relative to true north |
| | When the location was determined |
| | Floor of a building, if available |
| | Info about the location source |
Power Optimization Guidelines
Choose the most power-efficient service for your use case:
-
Visits service () — Most power-efficient. Reports places visited and time spent. Good for: check-in apps, travel logs.
startMonitoringVisits() -
Significant-change service () — Low power, uses Wi-Fi/cellular only. Good for: approximate location tracking.
startMonitoringSignificantLocationChanges() -
Standard location service () — Configurable accuracy via
startUpdatingLocation(). Good for: navigation, fitness tracking.desiredAccuracy -
Live updates () — Modern async API with configurable activity types. Good for: any new project on iOS 17+.
CLLocationUpdate.liveUpdates()
Desired Accuracy Constants
| Constant | Description |
|---|---|
| Highest precision, most power |
| Best available accuracy |
| Within ~10 meters |
| Within ~100 meters |
| Within ~1 km |
| Within ~3 km |
| Deliberately reduced accuracy |
Platform Considerations
- visionOS: Location services are limited. Background updates are not supported. Region monitoring methods do nothing for compatible iPad/iPhone apps running in visionOS.
- macOS: Apps are not suspended in background, so no special background capability needed.
- watchOS: Supports background location with capability. Use .
CLBackgroundActivitySession - Widgets: Check for widget eligibility.
isAuthorizedForWidgetUpdates
Common Pitfalls
- Always check — negative values mean the coordinate is invalid.
horizontalAccuracy - Do not assume location is immediately available after starting services.
- Handle authorization changes gracefully; users can revoke at any time via Settings.
- Geocoder requests are rate-limited; cache results and do not geocode on every location update.
- The system can pause location updates automatically. Set and
pausesLocationUpdatesAutomaticallyto help CoreLocation make good decisions.activityType - For background updates on iOS: add the "Location updates" background mode capability
AND set on the location manager.
allowsBackgroundLocationUpdates = true