【问题标题】:watchOS didUpdateLocation freezes during location changewatchOS didUpdateLocation 在位置更改期间冻结
【发布时间】:2021-12-03 22:38:18
【问题描述】:

我正在 SwiftUI 中为 watchOS 开发一个正在运行的应用程序。问题是,当我开始跑步时,测量工作正常,如0.55 0.56 0.57 km 等。然后它随机冻结,并从0.57 直接跳到0.71。即使总距离有时也不准确。当我查看跑步地图时,有时会看到曲线中的尖角和直线,这意味着测量非常不准确。操作系统是 watchOS 8.0。我试过kCLLocationAccuracyBest 无济于事。

我在一个名为 DistanceObservable 的 ObservableObject 中使用了 CLLocationManager,并且我在 iOS 应用程序中有这个精确的代码,可以完美地测量距离。

... @Published var distance: Double = 0.0
func startUpdate() {
        self.manager = CLLocationManager()
        self.manager?.delegate = self
        self.manager?.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
        self.manager?.requestWhenInUseAuthorization()
        self.manager?.distanceFilter = 10.0
        self.manager?.allowsBackgroundLocationUpdates = true
        self.manager?.startUpdatingLocation()
}

这是我的 watchOS didUpdateLocations 方法。

 func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    var locations = locations

        for newLocation in locations {
            let howRecent = newLocation.timestamp.timeIntervalSinceNow
            guard newLocation.horizontalAccuracy < 20 && abs(howRecent) < 10 else { continue }
            
            if let lastLocation = locationList.last {
                let delta = newLocation.distance(from: lastLocation)
                
                if (delta < 60) { // To prevent inaccurate "jumps" in distance
                    distance = distance + delta
                    
                    if UserDefaults.standard.value(forKey: "hasSet") as!Bool == false {
                        distance = 0
                        locations.removeAll()
                        UserDefaults.standard.setValue(true, forKey: "hasSet")
                    }
                    
                    latPoints.append(Double(locationList.last!.coordinate.latitude))
                    lonPoints.append(Double(locationList.last!.coordinate.longitude))
                }
            }
            
            locationList.append(newLocation)
    }
 }

最后我在 SwiftUI 视图中使用了@EnvironmentObject

struct MyView: View {
    @EnvironmentObject var loc: DistanceObservable
    var body: some View {
        Text("\(loc.distance)")
    }
}

【问题讨论】:

  • 您确定手表没有处于非活动状态或进入后台吗?见Working with the watchOS App Life Cycle。为了节省电池,手表与手机不同。您正在做的事情对手表来说非常密集。此外,还为这种情况添加了一些 API。底线是应用程序不会将 1:1 从 iOS 转换为 watchOS。这是其中之一。
  • 我已经通过添加 HealtKit 解决了这个问题。你可以在下面看到答案。谢谢!

标签: swift swiftui core-location watchos observableobject


【解决方案1】:

我已经通过开始新的 HealthKit 锻炼解决了这个问题。

  1. import HealthKit
  2. 添加对ObservableObject 及其方法的一致性
class SwiftUILocation: NSObject, CLLocationManagerDelegate, ObservableObject, HKWorkoutSessionDelegate, HKLiveWorkoutBuilderDelegate  {

 func workoutBuilder(_ workoutBuilder: HKLiveWorkoutBuilder, didCollectDataOf collectedTypes: Set<HKSampleType>) {
        print("A")
    }
    
    func workoutBuilderDidCollectEvent(_ workoutBuilder: HKLiveWorkoutBuilder) {
        print("B")
    }
    
    func workoutSession(_ workoutSession: HKWorkoutSession, didChangeTo toState: HKWorkoutSessionState, from fromState: HKWorkoutSessionState, date: Date) {
        print("C")
    }
    
    func workoutSession(_ workoutSession: HKWorkoutSession, didFailWithError error: Error) {
        print("D")
    }
    
//.. rest of the code
}

  1. 在锻炼开始时启动 HealthKit
 func startHealtKit(){
        let configuration = HKWorkoutConfiguration()
        configuration.activityType = .running
        configuration.locationType = .outdoor
           
        do {
            self.workoutSession = try HKWorkoutSession(healthStore: healthStore,
                                               configuration:configuration)
            
            self.builder = self.workoutSession?.associatedWorkoutBuilder()
            self.builder?.dataSource = HKLiveWorkoutDataSource(healthStore: healthStore,
                                                               workoutConfiguration: configuration)
            
            self.workoutSession?.delegate = self
            self.builder?.delegate = self
            self.workoutSession?.startActivity(with: Date())
            self.builder?.beginCollection(withStart: Date()) { (success, error) in
                // Indicate that the session has started.
            }
        }
        catch {
            print("HealthKit problem \(error.localizedDescription)")
         
        }
    }
  1. 在锻炼结束时停止 HealtkKit

  func stopHealthKit(){
        self.builder?.workoutSession?.stopActivity(with: Date())
        
        self.builder?.endCollection(withEnd: Date()) { (success, error) in
            // Indicate that the session has started.
        }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-15
    • 2018-07-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多