iOS HealthKit - how to get the absolutely latest, current heart rate, like the watch heart rate complication?

1.6k Views Asked by At

I have the following function that gets the recent heart rate from the HealthKit. When I examine the sample received, it often has a timestamp within the last 5 minutes. However, if I look at the Apple Watch Heart Rate complication, it sometimes has a different value like :

  • I see: 84 BPM 5 MIN AGO
  • Apple Watch can show either 84 BPM 5 MIN AGO or something like 80 BPM NOW

I tried experimenting with the end dates and using "strict end date", but still see that the data I get from healthkit often lags behind the apple watch heart rate complication.

Is there a way for me to query the latest heart rate right on the watch (skipping health kit)? Is there a way to ask the apple watch to take a heart rate measurement right now?

static func getCurrentHeartRate () {
    guard let sampleType = HKObjectType.quantityType(forIdentifier: .heartRate) else {
        return}

    let predicate = HKQuery
        .predicateForSamples(
            withStart: Date().addingTimeInterval(-3600),
            end: Date(),
            options: [])

    let sortDescriptor = NSSortDescriptor(
        key: HKSampleSortIdentifierStartDate,
        ascending: false)
    let query = HKSampleQuery(sampleType: sampleType,
                              predicate: predicate,
                              limit: Int(1),
                              sortDescriptors: [sortDescriptor]) { query, results, error in

                                guard let samples = results as? [HKQuantitySample] else {

                                    return
                                }
                                for s in samples {
                                    print("Recent heart rate: \(s.heartRateString())")
                                }
    }
    HKHealthStore().execute(query)
}

extension HKQuantitySample {
    func heartRateString() -> String {
        let date = self.startDate
        let updateString = "\(heartRateStringShort())\(date.timeAgoString())"
        return updateString
    }

    func heartRateStringShort() -> String {

        let heartRateUnit = HKUnit(from: "count/min")
        let heartRate = Int(self.quantity.doubleValue(for: heartRateUnit))

        let updateString = "\(heartRate) BPM"
        return updateString
    }
}
1

There are 1 best solutions below

0
On

If you start a workout on the watch you can get heart rate updates every few seconds. Look up how to setup HKLiveWorkoutBuilder

Without HKLiveWorkoutBuilder it won't update as fast.