Heart Rate data on apple Watch
There is no direct way to access any sensors on the Apple Watch. You will have to rely on access from HealthKit.
An Apple evangelist said this
It is not possible to create a heart monitor app at this time. The data isn't guaranteed to be sent to iPhone in real-time, so you won't be able to determine what's going on in any timely fashion.
See https://devforums.apple.com/message/1098855#1098855
After exploring HealthKit and WatchKit Extension, My findings are as follows:
We do not need the WatchKit Extension to get the Heart Rate Data.
You just need to have an iPhone with paired Apple watch (which is obvious)
The Default Apple Watch Heart Rate monitor app updates the HealthKit data immediately only when it is in the foreground.
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.
To get the Heart rate data from the HealthKit following query needs to be fired periodically.
func getSamples() { let heathStore = HKHealthStore() let heartrate = HKQuantityType.quantityType(forIdentifier: .heartRate) let sort: [NSSortDescriptor] = [ .init(key: HKSampleSortIdentifierStartDate, ascending: false) ] let sampleQuery = HKSampleQuery(sampleType: heartrate!, predicate: nil, limit: 1, sortDescriptors: sort, resultsHandler: resultsHandler) heathStore.execute(sampleQuery) } func resultsHandler(query: HKSampleQuery, results: [HKSample]?, error: Error?) { guard error == nil else { print("cant read heartRate data", error!) return } guard let sample = results?.first as? HKQuantitySample else { return } // let heartRateUnit: HKUnit = .init(from: "count/min") // let doubleValue = sample.quantity.doubleValue(for: heartRateUnit) print("heart rate is", sample) }
Please update me if anyone gets more information.
Happy Coding.
Update
I've updated your code to be clear and general, and be aware that you need to get authorization for reading HeathKit data and adding info.plist
key Privacy - Health Records Usage Description
Heart Rate Raw Data information is now available in Watchkit for watchOS 2.0
.
WatchOS 2
includes many enhancements to other existing frameworks such as HealthKit
, enabling access to the health sensors that access heart rate and health information in real-time.
You could check this information in the following session which is total 30 minutes presentation.If you do not want to watch entire session, then you directly jump to Healthkit API
features which is in between 25-28 min:
WatchKit for watchOS 2.0 Session in WWDC 2015
Here is the source code implementation link
As stated in the HKWorkout Class Reference:
The
HKWorkout
class is a concrete subclass of theHKSample
class.HealthKit
uses workouts to track a wide range of activities. The workout object not only stores summary information about the activity (for example, duration, total distance, and total energy burned), it also acts as a container for other samples. You can associate any number of samples with a workout. In this way, you can add detailed information relevant to the workout.
In that given link, the following part of the code defines sample rate of heartRate
NSMutableArray *samples = [NSMutableArray array];
HKQuantity *heartRateForInterval =
[HKQuantity quantityWithUnit:[HKUnit unitFromString:@"count/min"]
doubleValue:95.0];
HKQuantitySample *heartRateForIntervalSample =
[HKQuantitySample quantitySampleWithType:heartRateType
quantity:heartRateForInterval
startDate:intervals[0]
endDate:intervals[1]];
[samples addObject:heartRateForIntervalSample];
As they state there:
You need to fine tune the exact length of your associated samples based on the type of workout and the needs of your app. Using 5 minute intervals minimizes the amount of memory needed to store the workout , while still providing a general sense of the change in intensity over the course of a long workout. Using 5 second intervals provides a much-more detailed view of the workout, but requires considerably more memory and processing.
You can get heart rate data by starting a workout and query heart rate data from healthkit.
Ask for premission for reading workout data.
HKHealthStore *healthStore = [[HKHealthStore alloc] init]; HKQuantityType *type = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate]; HKQuantityType *type2 = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning]; HKQuantityType *type3 = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierActiveEnergyBurned]; [healthStore requestAuthorizationToShareTypes:nil readTypes:[NSSet setWithObjects:type, type2, type3, nil] completion:^(BOOL success, NSError * _Nullable error) { if (success) { NSLog(@"health data request success"); }else{ NSLog(@"error %@", error); } }];
In AppDelegate on iPhone, respond this this request
-(void)applicationShouldRequestHealthAuthorization:(UIApplication *)application{ [healthStore handleAuthorizationForExtensionWithCompletion:^(BOOL success, NSError * _Nullable error) { if (success) { NSLog(@"phone recieved health kit request"); } }]; }
Then implement
Healthkit Delegate
:-(void)workoutSession:(HKWorkoutSession *)workoutSession didFailWithError:(NSError *)error{ NSLog(@"session error %@", error); } -(void)workoutSession:(HKWorkoutSession *)workoutSession didChangeToState:(HKWorkoutSessionState)toState fromState:(HKWorkoutSessionState)fromState date:(NSDate *)date{ dispatch_async(dispatch_get_main_queue(), ^{ switch (toState) { case HKWorkoutSessionStateRunning: //When workout state is running, we will excute updateHeartbeat [self updateHeartbeat:date]; NSLog(@"started workout"); break; default: break; } }); }
Now it's time to write
**[self updateHeartbeat:date]**
-(void)updateHeartbeat:(NSDate *)startDate{ //first, create a predicate and set the endDate and option to nil/none NSPredicate *Predicate = [HKQuery predicateForSamplesWithStartDate:startDate endDate:nil options:HKQueryOptionNone]; //Then we create a sample type which is HKQuantityTypeIdentifierHeartRate HKSampleType *object = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate]; //ok, now, create a HKAnchoredObjectQuery with all the mess that we just created. heartQuery = [[HKAnchoredObjectQuery alloc] initWithType:object predicate:Predicate anchor:0 limit:0 resultsHandler:^(HKAnchoredObjectQuery *query, NSArray<HKSample *> *sampleObjects, NSArray<HKDeletedObject *> *deletedObjects, HKQueryAnchor *newAnchor, NSError *error) { if (!error && sampleObjects.count > 0) { HKQuantitySample *sample = (HKQuantitySample *)[sampleObjects objectAtIndex:0]; HKQuantity *quantity = sample.quantity; NSLog(@"%f", [quantity doubleValueForUnit:[HKUnit unitFromString:@"count/min"]]); }else{ NSLog(@"query %@", error); } }]; //wait, it's not over yet, this is the update handler [heartQuery setUpdateHandler:^(HKAnchoredObjectQuery *query, NSArray<HKSample *> *SampleArray, NSArray<HKDeletedObject *> *deletedObjects, HKQueryAnchor *Anchor, NSError *error) { if (!error && SampleArray.count > 0) { HKQuantitySample *sample = (HKQuantitySample *)[SampleArray objectAtIndex:0]; HKQuantity *quantity = sample.quantity; NSLog(@"%f", [quantity doubleValueForUnit:[HKUnit unitFromString:@"count/min"]]); }else{ NSLog(@"query %@", error); } }]; //now excute query and wait for the result showing up in the log. Yeah! [healthStore executeQuery:heartQuery]; }
You also have a turn on Healthkit in capbilities. Leave a comment below if you have any questions.