watchOS didUpdateLocation 在位置更改期间冻结

watchOS didUpdateLocation freezes during location change

我正在为 watchOS 在 SwiftUI 中开发一个 运行ning 应用程序。问题是,当我启动 运行 时,测量工作正常 0.55 0.56 0.57 公里等。然后它随机冻结,并从 0.57 直接跳到 0.71。甚至总距离有时也不准确。当我查看运行的地图时,有时会看到尖角和曲线中的直线,这意味着测量非常不准确。 OS 是 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()
}

这是我的watchOSdidUpdateLocations方法。

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

我已经通过开始新的 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.
        }
    }