diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_Vitals.h b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_Vitals.h index f80c7b66..2b7fd09f 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_Vitals.h +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_Vitals.h @@ -9,6 +9,7 @@ @interface RCTAppleHealthKit (Methods_Vitals) +- (void)vitals_saveHeartRateSample:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback; - (void)vitals_getHeartRateSamples:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback; - (void)vitals_getRestingHeartRate:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback; - (void)vitals_getWalkingHeartRateAverage:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback; diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_Vitals.m b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_Vitals.m index 473a7c5c..62d1c7c6 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_Vitals.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_Vitals.m @@ -12,6 +12,33 @@ @implementation RCTAppleHealthKit (Methods_Vitals) +- (void)vitals_saveHeartRateSample:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback +{ + NSDate *timeHeartRateSampleWasTaken = [RCTAppleHealthKit dateFromOptions:input key:@"date" withDefault:[NSDate date]]; + double heartRateValue = [RCTAppleHealthKit doubleFromOptions:input key:@"value" withDefault:-99]; + if(heartRateValue == -99){ + callback(@[RCTMakeError(@"heartRateValue is required in options", nil, nil)]); + return; + } + + HKUnit *count = [HKUnit countUnit]; + HKUnit *minute = [HKUnit minuteUnit]; + HKUnit *unit = [RCTAppleHealthKit hkUnitFromOptions:input key:@"unit" withDefault:[count unitDividedByUnit:minute]]; + + HKQuantitySample* heartRate = [HKQuantitySample quantitySampleWithType:[HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate] + quantity:[HKQuantity quantityWithUnit:unit doubleValue:heartRateValue] + startDate:timeHeartRateSampleWasTaken + endDate:timeHeartRateSampleWasTaken]; + + [self.healthStore saveObject:heartRate withCompletion:^(BOOL success, NSError *error) { + if (!success) { + NSLog(@"An error occured saving the heart rate sample: %@", error); + callback(@[RCTMakeError(@"An error occured saving the heart rate sample", error, nil)]); + return; + } + callback(@[[NSNull null], @true]); + }]; +} - (void)vitals_getHeartRateSamples:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback { diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+TypesAndPermissions.m b/RCTAppleHealthKit/RCTAppleHealthKit+TypesAndPermissions.m index 95a187f7..237846dc 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+TypesAndPermissions.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit+TypesAndPermissions.m @@ -385,6 +385,9 @@ - (nullable HKObjectType *)getWritePermFromText:(nonnull NSString*) key { if ([@"BloodAlcoholContent" isEqualToString: key]) { return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodAlcoholContent]; } + if ([@"HeartRate" isEqualToString: key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate]; + } return nil; } diff --git a/RCTAppleHealthKit/RCTAppleHealthKit.m b/RCTAppleHealthKit/RCTAppleHealthKit.m index 2bc0a363..e8ddce17 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit.m @@ -363,6 +363,12 @@ + (BOOL)requiresMainQueueSetup [self getWater:input callback:callback]; } +RCT_EXPORT_METHOD(saveHeartRateSample:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback) +{ + [self _initializeHealthStore]; + [self vitals_saveHeartRateSample:input callback:callback]; +} + RCT_EXPORT_METHOD(getWaterSamples:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback) { [self _initializeHealthStore]; diff --git a/README.md b/README.md index 3c2ce098..604dc175 100644 --- a/README.md +++ b/README.md @@ -256,6 +256,7 @@ All the documentation is under the [docs](/docs) folder. They are split into the - [getBloodPressureSamples](/docs/getBloodPressureSamples.md) - [getElectrocardiogramSamples](/docs/getElectrocardiogramSamples.md) +- [saveHeartRateSample](/docs/saveHeartRateSample.md) - [getHeartRateSamples](/docs/getHeartRateSamples.md) - [getHeartRateVariabilitySamples](/docs/getHeartRateVariabilitySamples.md) - [getHeartbeatSeriesSamples](/docs/getHeartbeatSeriesSamples.md) diff --git a/docs/saveHeartRateSample.md b/docs/saveHeartRateSample.md new file mode 100644 index 00000000..ef2263ec --- /dev/null +++ b/docs/saveHeartRateSample.md @@ -0,0 +1,33 @@ +# saveHeartRateSample + +Save a Heart Rate sample to Healthkit + +`saveHeartRateSample` accepts an options object containing a numeric heart rate value in Beats per minute (BPM). +In the example below a heart rate sample of 72BPM is added to Healthkit. + +Example input options: + +```javascript +let options = { + value: 72, // Amount in BPM + date: (new Date(2018,10,1)).toISOString(), // Optional, time when the Heart Rate was logged +} +``` + +Call the method: + +```javascript +AppleHealthKit.saveHeartRateSample((options: Object), (err: Object, results: boolean) => { + if (err) { + console.log('Error saving Heart Rate to Healthkit: ', err) + return + } + // Heart Rate successfully saved +}) +``` + +Example output: + +```json +1 +``` diff --git a/index.d.ts b/index.d.ts index 02f04ac9..a6c14fc4 100644 --- a/index.d.ts +++ b/index.d.ts @@ -235,6 +235,11 @@ declare module 'react-native-health' { callback: (err: string, results: HealthValue) => void, ): void + saveHeartRateSample( + options: HealthValueOptions, + callback: (error: string, result: HealthValue) => void, + ): void + getWaterSamples( options: HealthInputOptions, callback: (err: string, results: Array) => void,