Fetching current location in iOS 14 Widget

喜夏-厌秋 提交于 2020-12-25 04:02:48

问题


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?


回答1:


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)
        .......
    })
}


来源:https://stackoverflow.com/questions/63844536/fetching-current-location-in-ios-14-widget

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!