【问题标题】:Fetching current location in iOS 14 Widget在 iOS 14 小部件中获取当前位置
【发布时间】:2020-12-29 19:52:21
【问题描述】:

有没有人尝试在 iOS 14 Widget 中更新用户的位置? 在阅读了 Apple 开发者论坛后,我提出了 CLLocationManager 的写作包装器并以这种方式使用它:

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

并以这种方式使用它:

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

我在 Widget 的 info.plist 中也有这两个条目:

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

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

当 locationManager.requestLocation() 被调用时,授权状态为 authorisedWhenInUse,但委托的方法永远不会被调用。我错过了什么?

【问题讨论】:

    标签: ios swift core-location widgetkit


    【解决方案1】:

    首先,我看到的明显问题:

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

    NSLocationUsageDescription 已弃用:Apple Documentation,因此您应该改用 NSLocationWhenInUseUsageDescriptionNSLocationAlwaysAndWhenInUseUsageDescription。请务必在主应用程序Info.plist 中包含您选择的权限

    另外,在

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

    可能有问题,因为它可以从后台线程调用,所以我会像这样重构你的WidgetLocationManager

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

    然后像这样使用它:

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

    【讨论】:

    • 不幸的是,这没有帮助。
    • 所以问题仍然是 didUpdateLocations 没有被调用?您是否检查过是否调用了didFailWithError,如果是,那里的错误是什么?你是在设备上测试还是在模拟器上测试?
    • 我试过这个,它有点工作,它有利于获取当时的当前位置。但是您如何跟踪位置变化,以便自动刷新小部件?应该使用什么样的时间线刷新策略?您是否只是每隔几分钟刷新一次并一次又一次地检查当前位置?
    • @ZS 不,不断刷新位置小部件是个坏主意,您应该在主应用程序中管理位置更新,使用startUpdatingLocationdidUpdateLocations,保存以前的更新位置和与新的相比。如果 2 个位置之间的距离大于您认为显着位置变化的距离,请致电 WidgetCenter.shared.reloadTimelines(ofKind:) 以刷新小部件。如果您希望这发生在后台,那么您还应该使用后台位置更新并在应用程序进入后台时使用startMonitoringSignificantLocationChanges
    • @Mr.Zystem 我目前在我的应用程序中使用NSLocationWhenInUseUsageDescription ,它用于主应用程序而不是小部件。如果您使用NSLocationAlwaysAndWhenInUseUsageDescription ,这并不意味着小部件也会不停地更新位置。
    猜你喜欢
    • 2020-08-02
    • 2021-01-04
    • 1970-01-01
    • 2015-07-12
    • 2023-03-18
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    相关资源
    最近更新 更多