Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 801
Nikita Zernov Avatar asked Sep 11 '20 09:09

Nikita Zernov


People also ask

Is there a widget for location on iPhone?

With iOS 14 and later, you can configure your widgets. For example, you can edit the Weather widget to see the forecast for your current location or a different location. Here's how: Touch and hold a widget to open the quick actions menu.

Is there a widget for location services?

The My Location widget allows the network to detect your physical location and zoom the map to it. The location can be highlighted if necessary. The widget takes advantage of HTML geolocation. When the app runs on desktops, it uses the browser on the network to detect the location.

How do you refresh iPhone widgets?

Tap On The Widget Sometimes all you need to do to update the information display on a widget is to tap on it and open the app. When the app opens, its content will refresh, which should refresh the widget too.

How to change widget location on iPhone and iPad?

Open Settings on your iPhone or iPod touch with iOS 14+ or your iPad with iPadOS 14+. Choose “Privacy” in the root list. Tap “Location Services” at the very top of the list. Tap a listed app that has a widget, such as Weather. Now choose between the available options to manage widget location access.

What are widgets in iOS 14?

One to coolest new features in iOS 14 is widgets, which allow you to view important information from critical apps at a glance wherever you want from your iPhone Home Screen. The widgets come in different sizes and, at least for now, are available exclusively for native apps. Here’s how to use them on the iPhone.

How do widget permissions work in iOS and iPadOS 14?

Before iOS and iPadOS 14 came along, a widget would simply inherit location permissions from its container app. For instance, setting location access for the Weather app to “Always” in iOS 13 would automatically give the same location permission to the accompanying widget.

How to get accurate location in iOS 14?

Now, when you run the code above on your device, you’ll get the following revamped prompt in iOS 14: Screenshot from the author’s phone. By toggling the “Precise” button, you can choose to allow approximate or accurate location access. Now, there could be a use case where you are required to only access a user’s accurate location.


1 Answers

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)
        .......
    })
}
like image 143
sabius Avatar answered Sep 19 '22 03:09

sabius