HealthKit 会不断更新模拟器上的样本数据,但不会更新 Apple Watch 上的实际数据

Posted

技术标签:

【中文标题】HealthKit 会不断更新模拟器上的样本数据,但不会更新 Apple Watch 上的实际数据【英文标题】:HealthKit keeps updating the sample data on a simulator, but not the actual data on apple watch 【发布时间】:2021-09-13 12:39:41 【问题描述】:

我刚开始使用 WWDC 开源学习 swift。我正在学习如何创建手表操作系统锻炼应用程序。当我在模拟器上运行它时,它会不断更新示例数据,但在我的 Apple Watch 上,当我运行它时,它不会不断更新实时锻炼数据。我确信我必须处理下面的代码,但是

extension WorkoutManager: HKLiveWorkoutBuilderDelegate 
    func workoutBuilderDidCollectEvent(_ workoutBuilder: HKLiveWorkoutBuilder) 
    

    func workoutBuilder(_ workoutBuilder: HKLiveWorkoutBuilder, didCollectDataOf collectedTypes: Set<HKSampleType>) 
        for type in collectedTypes 
            guard let quantityType = type as? HKQuantityType else 
                return // Nothing to do.
            

            let statistics = workoutBuilder.statistics(for: quantityType)

            // Update the published values.
            updateForStatistics(statistics)
        
    

我不知道调用 HealthKit 时究竟发生了什么,我从 WWDC 示例中获取了大部分代码。

import Foundation
import HealthKit

class WorkoutManager: NSObject, ObservableObject 
    var selectedWorkout: HKWorkoutActivityType? 
        didSet 
            guard let selectedWorkout = selectedWorkout else  return 
            startWorkout(workoutType: selectedWorkout)
        
    
    
    @Published var showingSummaryView: Bool = false 
        didSet 
            if showingSummaryView == false 
                resetWorkout()
            
        
    
    
    let healthStore = HKHealthStore()
    var session: HKWorkoutSession?
    var builder: HKLiveWorkoutBuilder?
    
    func startWorkout(workoutType: HKWorkoutActivityType) 
        let configuration = HKWorkoutConfiguration()
        configuration.activityType = workoutType
        configuration.locationType = .outdoor
            // Create the session and obtain the workout builder.
        do 
            session = try HKWorkoutSession(healthStore: healthStore, configuration: configuration)
            builder = session?.associatedWorkoutBuilder()
         catch 
            // Handle any exceptions.
            return
        
        // Set the workout builder's data source.
        builder?.dataSource = HKLiveWorkoutDataSource(healthStore: healthStore,
                                                         workoutConfiguration: configuration)
        
        session?.delegate = self
        builder?.delegate = self

        // Start the workout session and begin data collection.
        let startDate = Date()
        session?.startActivity(with: startDate)
        builder?.beginCollection(withStart: startDate)  (success, error) in
                // The workout has started.
        
    
    func requestAuthorization() 
        // The quantity type to write to the health store.
        let typesToShare: Set = [
            HKQuantityType.workoutType()
        ]

        // The quantity types to read from the health store.
        let typesToRead: Set = [
            HKQuantityType.quantityType(forIdentifier: .heartRate)!,
            HKObjectType.activitySummaryType()
        ]

        // Request authorization for those quantity types.
        healthStore.requestAuthorization(toShare: typesToShare, read: typesToRead)  (success, error) in
            // Handle error.
        
    
    // MARK: - Session State Control

    // The app's workout state.
    @Published var running = false

    func togglePause() 
        if running == true 
            self.pause()
         else 
            resume()
        
    

    func pause() 
        session?.pause()
    

    func resume() 
        session?.resume()
    

    func endWorkout() 
        session?.end()
        showingSummaryView = true
    
    // MARK: - Workout Metrics
    @Published var averageHeartRate: Double = 0
    @Published var heartRate: Double = 0
    @Published var workout: HKWorkout?
   
    func updateForStatistics(_ statistics: HKStatistics?) 
        guard let statistics = statistics else  return 

        DispatchQueue.main.async 
            switch statistics.quantityType 
            case HKQuantityType.quantityType(forIdentifier: .heartRate):
                let heartRateUnit = HKUnit.count().unitDivided(by: HKUnit.minute())
                self.heartRate = statistics.mostRecentQuantity()?.doubleValue(for: heartRateUnit) ?? 0
                self.averageHeartRate = statistics.averageQuantity()?.doubleValue(for: heartRateUnit) ?? 0
            default:
                return
            
        
    

    func resetWorkout() 
        selectedWorkout = nil
        builder = nil
        workout = nil
        session = nil
        averageHeartRate = 0
        heartRate = 0
    



extension WorkoutManager: HKWorkoutSessionDelegate 
    func workoutSession(_ workoutSession: HKWorkoutSession, didChangeTo toState: HKWorkoutSessionState,
                        from fromState: HKWorkoutSessionState, date: Date) 
        DispatchQueue.main.async 
            self.running = toState == .running
        

        // Wait for the session to transition states before ending the builder.
        if toState == .ended 
            builder?.endCollection(withEnd: date)  (success, error) in
                self.builder?.finishWorkout  (workout, error) in
                    DispatchQueue.main.async 
                        self.workout = workout
                    
                
            
        
    

    func workoutSession(_ workoutSession: HKWorkoutSession, didFailWithError error: Error) 

    


extension WorkoutManager: HKLiveWorkoutBuilderDelegate 
    func workoutBuilderDidCollectEvent(_ workoutBuilder: HKLiveWorkoutBuilder) 
    

    func workoutBuilder(_ workoutBuilder: HKLiveWorkoutBuilder, didCollectDataOf collectedTypes: Set<HKSampleType>) 
        for type in collectedTypes 
            guard let quantityType = type as? HKQuantityType else 
                return // Nothing to do.
            

            let statistics = workoutBuilder.statistics(for: quantityType)

            // Update the published values.
            updateForStatistics(statistics)
        
    

【问题讨论】:

developer.apple.com/wwdc21/10009 【参考方案1】:

您是否在Info.plist 中启用了Workout processing 后台模式?

【讨论】:

是的,它已启用。

以上是关于HealthKit 会不断更新模拟器上的样本数据,但不会更新 Apple Watch 上的实际数据的主要内容,如果未能解决你的问题,请参考以下文章

HealthKit 授权已授予并在模拟器上工作,但不在实际设备上

此 HealthKit 错误的原因是啥:“将样本添加到锻炼时发生错误”?

此 HealthKit 错误的原因是啥:“将样本添加到锻炼时发生错误”?

Swift HealthKit 触发心率样本

HealthKit:与提供的锻炼相关的样本删除问题

HealthKit:与提供的锻炼相关的样本删除问题