使用 HKHeartbeatSeriesSample 从 Apple Watch 获取实时心跳数据

Posted

技术标签:

【中文标题】使用 HKHeartbeatSeriesSample 从 Apple Watch 获取实时心跳数据【英文标题】:Real time heart beat data from Apple Watch using HKHeartbeatSeriesSample 【发布时间】:2020-01-21 01:38:21 【问题描述】:

我正在尝试实时访问从 Apple Watch 记录的心跳数据。使用 HKWorkoutSession,我可以每 5 秒回调一次workoutBuilder didCollectDataOf,并提供心率(心跳/分钟)数据。

这对我的应用程序来说不够实时,因此我正在考虑为此目的使用新的(从 ios 13 和 watchOS 6.0 开始)HKHeartbeatSeriesSample(和相关类)。我的理解是,心跳数据的系列样本将以系列形式记录逐次心跳的测量值。

我能够让 API 工作并获得一些数据,但不是实时的——我获得的系列数据来自之前的一些记录(不清楚是什么触发了这些记录)。

这里是授权:

            let allTypes: Set<HKSampleType> = Set([
                HKObjectType.workoutType(),
                HKSeriesType.heartbeat(),
                HKObjectType.quantityType(forIdentifier: .heartRate)!,
                HKQuantityType.quantityType(forIdentifier: .heartRateVariabilitySDNN)!,
            ])

            healthStore.requestAuthorization(toShare: allTypes, read: allTypes)  (success, error) in
                ///...
                let workoutSession = WorkoutSession(healthStore: self.healthStore)
                workoutSession.startHeartbeatSampleQuery()
            

startHeartBeatSampleQuery:

            let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierStartDate,
                                                  ascending: false)

            // Query for the heartbeat samples from the specified heartbeat series.
            let heartbeatSeriesSampleQuery = HKSampleQuery(sampleType: HKSeriesType.heartbeat(),
                                                           predicate: nil,
                                                           limit: HKObjectQueryNoLimit,
                                                           sortDescriptors: [sortDescriptor]) 
                (query, results, error) in

                guard let samples = results, let sample = samples.first as? HKHeartbeatSeriesSample else 
                    print("NO SAMPLES MY FRIEND")
                    return
                

                let heartbeatSeriesQuery = HKHeartbeatSeriesQuery(heartbeatSeries: sample) 
                    (query, timeSinceSeriesStart, precededByGap, done, error) in

                    guard error == nil else 
                        print("error in HKHeartbeatSeriesQuery: \(String(describing: error))")
                        return
                    

                    print("timeSinceSeriesStart = \(timeSinceSeriesStart), precededByGap = \(precededByGap)")

                

                self.healthStore.execute(heartbeatSeriesQuery)
            

            completionHandler()

            self.healthStore.execute(heartbeatSeriesSampleQuery)
        

我从这个查询中得到的系列样本:

samples: [count=41 5D4F0C84-294D-41A7-8F64-B387A8E767A3 "Vishal’s Apple Watch" (6.1.1), "Watch3,2" (6.1.1)"Apple Watch"  (2020-01-18 12:12:06 -0800 - 2020-01-18 12:13:12 -0800), count=27 32B0B090-CDF8-48F5-BCF6-670982C426F3 "Vishal’s Apple Watch" (6.1.1), "Watch3,2" (6.1.1)"Apple Watch"  (2020-01-15 21:38:41 -0800 - 2020-01-15 21:39:46 -0800), count=67 B485328A-3EA1-49F2-8666-75B3B2143A05 "Vishal’s Apple Watch" (6.1.1), "Watch3,2" (6.1.1)"Apple Watch"  (2020-01-14 21:00:15 -0800 - 2020-01-14 21:01:17 -0800), count=48 9D550B3A-F325-4CA0-B5E7-43BA42E835ED "Vishal’s Apple Watch" (6.1.1), "Watch3,2" (6.1.1)"Apple Watch"  (2020-01-14 17:06:27 -0800 - 2020-01-14 17:07:33 -0800), count=50 278E1BF7-726B-443B-97C3-8BBA3DF06207 "Vishal’s Apple Watch" (6.1.1), "Watch3,2" (6.1.1)"Apple Watch"  (2020-01-13 12:04:28 -0800 - 2020-01-13 12:05:34 -0800), count=33 1215B2C4-F168-4EAD-9C35-5F734CC29637 "Vishal’s Apple Watch" (6.1.1), "Watch3,2" (6.1.1)"Apple Watch"  (2020-01-13 11:55:01 -0800 - 2020-01-13 11:56:06 -0800), count=48 EB2C64F9-9E81-4F5B-BA4A-62FA6816FE29 "Vishal’s Apple Watch" (6.1.1), "Watch3,2" (6.1.1)"Apple Watch"  (2020-01-11 12:20:36 -0800 - 2020-01-11 12:21:37 -0800), count=46 515D467A-51E9-490B-8082-5C8F541A0BD7 "Vishal’s Apple Watch" (6.1.1), "Watch3,2" (6.1.1)"Apple Watch"  (2020-01-11 11:01:38 -0800 - 2020-01-11 11:02:44 -0800)], sample: count=41 5D4F0C84-294D-41A7-8F64-B387A8E767A3 "Vishal’s Apple Watch" (6.1.1), "Watch3,2" (6.1.1)"Apple Watch"  (2020-01-18 12:12:06 -0800 - 2020-01-18 12:13:12 -0800)

最近的时间是 1/18,与我的活跃锻炼时段不对应 - 无论我是开始 HKWorkoutSession 还是在手表上手动进行锻炼,这似乎都没有改变。

但是系列中的数据正是我想要的;逐拍数据,例如:

timeSinceSeriesStart = 1.1875, precededByGap = false
timeSinceSeriesStart = 2.046875, precededByGap = false
timeSinceSeriesStart = 2.92578125, precededByGap = false
timeSinceSeriesStart = 3.8125, precededByGap = false
...

我是否错误地使用了 API?或者这不是获取实时心跳数据的可行方法吗?

【问题讨论】:

【参考方案1】:

没有一种方法可以比您使用锻炼会话 API 观察到的更精确地记录心率。在 Apple Watch 计算心率变异性时记录HKSeriesType.heartbeat() 类型的样本(请参阅样本类型heartRateVariabilitySDNN)。 HRV 由 Apple Watch 在后台定期计算。没有用于启动 HRV 读数的 API。

【讨论】:

谢谢!这很不幸,但我很欣赏这种清晰。想知道您是否可以帮助我正确解释我得到的心率数据——它是移动平均值(最后 60 秒)还是从最后 5 秒推断出来的? (如果您更愿意在此处回答,请在此处提问:***.com/questions/59833264/…) 是否有 API 可以手动启动采样以获取访问权限?

以上是关于使用 HKHeartbeatSeriesSample 从 Apple Watch 获取实时心跳数据的主要内容,如果未能解决你的问题,请参考以下文章

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?

今目标使用教程 今目标任务使用篇

Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份

Kettle java脚本组件的使用说明(简单使用升级使用)