I would like to collect the heart rate of the user programmatically by a watchkit extension, but not during a workout session.
As far as I know watchOS 3+ doesn't collect heart rate if the user is moving: however as soon as he's resting for a while (10 minutes ?) I'd like to get somehow the current bpm value by the HealthKit API.
Since you are having a companion iPhone app, you may query heart rate updates from there.
When the Default Apple Watch Heart Rate monitor app is in the Background, it updates the HealthKit data at the interval of 9-10 mins. This code should do the work:
import UIKit
import HealthKit
class ViewController: UIViewController {
@IBOutlet weak var heartRateLabel: UILabel!
@IBOutlet weak var timeStampLabel: UILabel!
var hkStore: HKHealthStore?
let heartRateUnit: HKUnit = HKUnit.count().unitDivided(by: .minute())
var healthStore: HKHealthStore?
override func viewDidLoad() {
super.viewDidLoad()
healthStore = HKHealthStore()
let sampleTypes = HKSampleType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate)!
healthStore?.requestAuthorization(toShare: [sampleTypes], read: [sampleTypes], completion: { (success, error) in
if (error != nil) {
print(error!.localizedDescription)
}
})
getSamples()
}
func getSamples() {
let heartrate = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.heartRate)
let sort = [
NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: false)
]
let sampleQuery = HKSampleQuery(sampleType: heartrate!, predicate: nil, limit: 1, sortDescriptors: sort, resultsHandler: { [unowned self] (query, results, error) in
if let results = results as? [HKQuantitySample]
{
let sample = results[0] as HKQuantitySample
let value = sample.quantity.doubleValue(for: self.heartRateUnit)
let rate = results[0]
print(value, rate)
self.updateHeartRate(samples: results)
}
})
healthStore?.execute(sampleQuery)
}
func updateHeartRate(samples: [HKSample]?) {
guard let heartRateSamples = samples as? [HKQuantitySample] else {return}
DispatchQueue.main.async {
guard let sample = heartRateSamples.first else{return}
let value = sample.quantity.doubleValue(for: self.heartRateUnit)
self.heartRateLabel.text = String(UInt16(value))
let date = sample.startDate
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd hh:mm:ss"
self.timeStampLabel.text = dateFormatter.string(from: date)
}
}
}
Notice that the query need to be fire periodically.