How to get Current Location with SwiftUI?
This code below works (Not production ready). Implementing the CLLocationManagerDelegate
works fine and the lastKnownLocation
is updated accordingly.
Don't forget to set the NSLocationWhenInUseUsageDescription
in your Info.plist
class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
private let manager = CLLocationManager()
var lastKnownLocation: CLLocation?
func startUpdating() {
manager.delegate = self
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print(locations)
lastKnownLocation = locations.last
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedWhenInUse {
manager.startUpdatingLocation()
}
}
}
I have written a one-file swift package with usage instructions on https://github.com/himbeles/LocationProvider. It provides a ObservableObject
-type wrapper class for CLLocationManager and its delegate.
There is a @Published
property location
which can directly be used in SwiftUI, as well as a PassthroughSubject<CLLocation, Never>
called locationWillChange
that you can subscribe to via Combine. Both update on every didUpdateLocations
event of the CLLocationManager
.
It also handles the case where location access has previously been denied: The default behavior is to present the user with a request to enable access in the app settings and a link to go there.
In SwiftUI (> iOS 14, > macOS 11), use as
import SwiftUI
import LocationProvider
struct ContentView: View {
@StateObject var locationProvider = LocationProvider()
var body: some View {
VStack{
Text("latitude \(locationProvider.location?.coordinate.latitude ?? 0)")
Text("longitude \(locationProvider.location?.coordinate.longitude ?? 0)")
}
.onAppear {
do {try locationProvider.start()}
catch {
print("No location access.")
locationProvider.requestAuthorization()
}
}
}
}