Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get Current Location with SwiftUI?

Trying to get current location with using swiftUI. Below code, couldn't initialize with didUpdateLocations delegate.

class GetLocation : BindableObject {
    var didChange = PassthroughSubject<GetLocation,Never>()

    var location : CLLocation {
        didSet {
            didChange.send(self)
        }
    }
    init() {}
}
like image 297
Görkem Aydın Avatar asked Jun 10 '19 20:06

Görkem Aydın


People also ask

How do I display a map in SwiftUI?

To display a map with the region of your choosing, follow these steps: import MapKit. Add a @State property to define a variable named region as a MKCoordinateRegion that specifies the center coordinate and zoom level for the map. Add a Map element to the body of the MapView and use the region as a parameter.

How do I ask a user for location in Swift?

You need to add a key NSLocationWhenInUseUsageDescription in yours info. plist file and in the value you write something that you want to show the user in the popup dialog. You need to test it on a real device cause Simulator accepts only custom locations. Select the Simulator -> Debug -> Location -> Custom Location...


3 Answers

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()
            }
        }
    }
}
like image 159
lsrggr Avatar answered Oct 19 '22 07:10

lsrggr


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()
        }
    }
}
like image 28
Viktor Gardart Avatar answered Oct 19 '22 05:10

Viktor Gardart


As of Xcode 11 beta 4, you will need to change didChange to willChange:

var willChange = PassthroughSubject<LocationManager, Never>()

var lastKnownLocation: CLLocation? {
    willSet {
        willChange.send(self)
    }
}
like image 3
MwcsMac Avatar answered Oct 19 '22 07:10

MwcsMac