Hello,
I am developing an Apple Watch app in Swift and SwiftUI that needs to receive real-time heartbeat data to visualize the time intervals between heartbeats. The app draws circles on the screen where the size and position of each circle are based on the time interval between consecutive heartbeats.
I am currently using the HKQuantityType
for .heartRate
from HealthKit to get heart rate data and calculate the intervals. However, I am wondering if this is the best approach for my requirement. I came across the HKElectrocardiogram
class, and I am not sure if it would be a better fit for obtaining real-time heartbeat intervals.
My questions are:
-
Real-Time Heartbeats:
- Is
HKQuantityType
for.heartRate
the most appropriate way to get real-time heartbeat data for calculating intervals between beats? - Can
HKElectrocardiogram
provide real-time heartbeat intervals, or is it more suited for detailed ECG recordings rather than instantaneous heartbeats?
- Is
-
Accuracy and Performance:
- Which method provides the most accurate and real-time data for heartbeat intervals?
- Are there any other APIs or services in the Apple Watch ecosystem that I should consider for this purpose?
-
Best Practices:
- What are the best practices for implementing real-time heartbeat monitoring in an Apple Watch app?
- Are there any sample projects or documentation that could help me understand the optimal way to achieve this?
Here is a brief overview of my current implementation using HKQuantityType
for .heartRate
:
import Foundation
import HealthKit
class HeartRateMonitor: NSObject, ObservableObject {
@Published var heartRate: Double = 0.0
@Published var intervals: [TimeInterval] = []
private var lastHeartRateTimestamp: Date?
private var healthStore: HKHealthStore?
private let heartRateQuantityType = HKObjectType.quantityType(forIdentifier: .heartRate)
private let appStartTime: Date
override init() {
self.appStartTime = Date()
super.init()
if HKHealthStore.isHealthDataAvailable() {
self.healthStore = HKHealthStore()
self.requestAuthorization()
}
}
private func requestAuthorization() {
guard let heartRateQuantityType = self.heartRateQuantityType else { return }
healthStore?.requestAuthorization(toShare: nil, read: [heartRateQuantityType]) { success, error in
if success {
self.startMonitoring()
}
}
}
func startMonitoring() {
guard let heartRateQuantityType = self.heartRateQuantityType else { return }
let query = HKAnchoredObjectQuery(
type: heartRateQuantityType,
predicate: nil,
anchor: nil,
limit: HKObjectQueryNoLimit) { (query, samples, deletedObjects, newAnchor, error) in
guard let samples = samples as? [HKQuantitySample] else { return }
self.process(samples: samples)
}
query.updateHandler = { (query, samples, deletedObjects, newAnchor, error) in
guard let samples = samples as? [HKQuantitySample] else { return }
self.process(samples: samples)
}
healthStore?.execute(query)
}
private func process(samples: [HKQuantitySample]) {
for sample in samples {
if sample.endDate > appStartTime {
let heartRateUnit = HKUnit.count().unitDivided(by: HKUnit.minute())
let heartRate = sample.quantity.doubleValue(for: heartRateUnit)
DispatchQueue.main.async {
self.heartRate = heartRate
if let lastTimestamp = self.lastHeartRateTimestamp {
let interval = sample.endDate.timeIntervalSince(lastTimestamp)
self.intervals.append(interval)
}
self.lastHeartRateTimestamp = sample.endDate
}
}
}
}
}
Thank you for your guidance and suggestions!
First, I probably don't call the HealthKit data "real-time". On the Apple Watch side, the data is only available for apps after it has been gathered from the sensors, processed, and saved to the HealthKit store. On the paired iPhone side, the data is only available after the HealthKit store is synchronized, which can take a while.
If you focus on heart rates, using HKAnchoredObjectQuery
to query the HKQuantityType(.heartRate)
samples is the right way to go, and so you are on the right track. HKAnchoredObjectQuery
triggers its updateHandler
when a new sample (after the specified anchor) becomes available, which is better than executing multiple sample queries (HKSampleQuery
). The same logic applies to other samples like HKElectrocardiogram
.
A heart rate sample doesn't have the heart beats though. If you'd look into heart beats, consider querying the heartbeat series samples (HKSeriesType.heartbeat()
). For more information, see HKHeartbeatSeriesSample and HKHeartbeatSeriesQuery.
In that matters, HealthKit also provides Heart rate variability (HRV) samples. See heartRateVariabilitySDNN.
Best,
——
Ziqiao Chen
Worldwide Developer Relations.