Nikita Zernov
Nikita Zernov

Reputation: 5635

Fetching current location in iOS 14 Widget

Has anyone tried to update user's location in iOS 14 Widget? After reading Apple Developer forums I've come up with the writing wrapper around CLLocationManager and using it this way:

class WidgetLocationManager: NSObject, CLLocationManagerDelegate {
    var locationManager: CLLocationManager? {
        didSet {
            self.locationManager!.delegate = self
        }
    }
    private var handler: ((CLLocation) -> Void)?
    
    func fetchLocation(handler: @escaping (CLLocation) -> Void) {
        self.handler = handler
        self.locationManager!.requestLocation()
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        self.handler!(locations.last!)
    }
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        print(error)
    }
}

And using it this way:

var widgetLocationManager = WidgetLocationManager()
    func getTimeline(for configuration: SelectPlaceIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {
        if widgetLocationManager.locationManager == nil {
            widgetLocationManager.locationManager = CLLocationManager()
            widgetLocationManager.locationManager!.requestWhenInUseAuthorization()
        }
        widgetLocationManager.fetchLocation(handler: { location in
            print(location)
            .......
        })
    }

I also have these 2 entries in Widget's info.plist:

<key>NSLocationUsageDescription</key>
<string>1</string>

<key>NSWidgetWantsLocation</key>
<true/>

When locationManager.requestLocation() is being called, authorisation status is authorisedWhenInUse, but delegate's method is never being called. What am I missing?

Upvotes: 11

Views: 5017

Answers (2)

Alex Lopez
Alex Lopez

Reputation: 11

Make sure you have both these plist values set in your widgets Info.plist file:

<key>NSWidgetWantsLocation</key>
<true/>
<key>NSLocationUsageDescription</key>
<string>Put some text here</string>

Upvotes: 1

sabius
sabius

Reputation: 784

First of all, the obvious problem that I see:

<key>NSLocationUsageDescription</key>
<string>1</string>

NSLocationUsageDescription is deprecated: Apple Documentation , so you should be using NSLocationWhenInUseUsageDescription or NSLocationAlwaysAndWhenInUseUsageDescription instead. Be sure to include the permission that you choose in main apps Info.plist as well

Additionally, creating CLLocationManager in

func getTimeline(for configuration: SelectPlaceIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {
    ...
}

might be problematic, since it can get called from background thread, so I would refactor your WidgetLocationManager like this:

class WidgetLocationManager: NSObject, CLLocationManagerDelegate {
    var locationManager: CLLocationManager? 
    private var handler: ((CLLocation) -> Void)?

    override init() {
        super.init()
        DispatchQueue.main.async {
            self.locationManager = CLLocationManager()
            self.locationManager!.delegate = self
            if self.locationManager!.authorizationStatus == .notDetermined {
                self.locationManager!.requestWhenInUseAuthorization()
            }
        }
    }
    
    func fetchLocation(handler: @escaping (CLLocation) -> Void) {
        self.handler = handler
        self.locationManager!.requestLocation()
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        self.handler!(locations.last!)
    }
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        print(error)
    }
}

and later use it like this:

var widgetLocationManager = WidgetLocationManager()

func getTimeline(for configuration: SelectPlaceIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {
    widgetLocationManager.fetchLocation(handler: { location in
        print(location)
        .......
    })
}

Upvotes: 10

Related Questions