Skip to content

Commit 8599baf

Browse files
authored
Merge pull request #1 from agencyenterprise/master
Sync with parent repo
2 parents a82d2d0 + 77554da commit 8599baf

34 files changed

+3405
-2609
lines changed

RCTAppleHealthKit/RCTAppleHealthKit+Methods_Body.h

+4
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@
2626
- (void)body_getWaistCircumferenceSamples:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback;
2727
- (void)body_saveWaistCircumference:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback;
2828

29+
- (void)body_getLatestPeakFlow:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback;
30+
- (void)body_getPeakFlowSamples:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback;
31+
- (void)body_savePeakFlow:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback;
32+
2933
- (void)body_getLatestBodyFatPercentage:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback;
3034
- (void)body_getBodyFatPercentageSamples:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback;
3135
- (void)body_saveBodyFatPercentage:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback;

RCTAppleHealthKit/RCTAppleHealthKit+Methods_Body.m

+75
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,81 @@ - (void)body_saveWaistCircumference:(NSDictionary *)input callback:(RCTResponseS
328328
}];
329329
}
330330

331+
- (void)body_getLatestPeakFlow:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback
332+
{
333+
HKQuantityType *peakFlowType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierPeakExpiratoryFlowRate];
334+
HKUnit *unit = [RCTAppleHealthKit hkUnitFromOptions:input key:@"unit" withDefault:[[HKUnit literUnit] unitDividedByUnit:[HKUnit minuteUnit]]];
335+
336+
[self fetchMostRecentQuantitySampleOfType:peakFlowType
337+
predicate:nil
338+
completion:^(HKQuantity *mostRecentQuantity, NSDate *startDate, NSDate *endDate, NSError *error) {
339+
if (error) {
340+
NSLog(@"error getting latest peak flow: %@", error);
341+
callback(@[RCTMakeError(@"error getting latest peak flow", error, nil)]);
342+
}
343+
else {
344+
// Determine the peak flow rate in the required unit.
345+
double peakFlow = [mostRecentQuantity doubleValueForUnit:unit];
346+
347+
NSDictionary *response = @{
348+
@"value" : @(peakFlow),
349+
@"startDate" : [RCTAppleHealthKit buildISO8601StringFromDate:startDate],
350+
@"endDate" : [RCTAppleHealthKit buildISO8601StringFromDate:endDate],
351+
};
352+
353+
callback(@[[NSNull null], response]);
354+
}
355+
}];
356+
}
357+
358+
- (void)body_getPeakFlowSamples:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback
359+
{
360+
HKQuantityType *peakFlowType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierPeakExpiratoryFlowRate];
361+
362+
HKUnit *unit = [RCTAppleHealthKit hkUnitFromOptions:input key:@"unit" withDefault:[[HKUnit literUnit] unitDividedByUnit:[HKUnit minuteUnit]]];
363+
364+
NSUInteger limit = [RCTAppleHealthKit uintFromOptions:input key:@"limit" withDefault:HKObjectQueryNoLimit];
365+
BOOL ascending = [RCTAppleHealthKit boolFromOptions:input key:@"ascending" withDefault:false];
366+
NSDate *startDate = [RCTAppleHealthKit dateFromOptions:input key:@"startDate" withDefault:nil];
367+
NSDate *endDate = [RCTAppleHealthKit dateFromOptions:input key:@"endDate" withDefault:[NSDate date]];
368+
if(startDate == nil){
369+
callback(@[RCTMakeError(@"startDate is required in options", nil, nil)]);
370+
return;
371+
}
372+
NSPredicate * predicate = [RCTAppleHealthKit predicateForSamplesBetweenDates:startDate endDate:endDate];
373+
374+
[self fetchQuantitySamplesOfType:peakFlowType
375+
unit:unit
376+
predicate:predicate
377+
ascending:ascending
378+
limit:limit
379+
completion:^(NSArray *results, NSError *error) {
380+
if(results){
381+
callback(@[[NSNull null], results]);
382+
} else {
383+
callback(@[RCTJSErrorFromNSError(error)]);
384+
}
385+
}];
386+
}
387+
388+
- (void)body_savePeakFlow:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback
389+
{
390+
double peakFlow = [RCTAppleHealthKit doubleValueFromOptions:input];
391+
NSDate *sampleDate = [RCTAppleHealthKit dateFromOptionsDefaultNow:input];
392+
HKUnit *peakFlowUnit = [RCTAppleHealthKit hkUnitFromOptions:input key:@"unit" withDefault:[[HKUnit literUnit] unitDividedByUnit:[HKUnit minuteUnit]]];
393+
394+
HKQuantity *peakFlowQuantity = [HKQuantity quantityWithUnit:peakFlowUnit doubleValue:peakFlow];
395+
HKQuantityType *peakFlowType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierPeakExpiratoryFlowRate];
396+
HKQuantitySample *peakFlowSample = [HKQuantitySample quantitySampleWithType:peakFlowType quantity:peakFlowQuantity startDate:sampleDate endDate:sampleDate];
397+
398+
[self.healthStore saveObject:peakFlowSample withCompletion:^(BOOL success, NSError *error) {
399+
if (!success) {
400+
callback(@[RCTJSErrorFromNSError(error)]);
401+
return;
402+
}
403+
callback(@[[NSNull null], @(peakFlow)]);
404+
}];
405+
}
331406

332407
- (void)body_getLatestBodyFatPercentage:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback
333408
{

RCTAppleHealthKit/RCTAppleHealthKit+Methods_Dietary.h

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
- (void)saveWater:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback;
1616
- (void)getWater:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback;
17+
- (void)getWaterSamples:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback;
1718

1819
- (void)dietary_getEnergyConsumedSamples:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback;
1920
- (void)dietary_getProteinSamples:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback;

RCTAppleHealthKit/RCTAppleHealthKit+Methods_Dietary.m

+35
Original file line numberDiff line numberDiff line change
@@ -533,4 +533,39 @@ - (void)getWater:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback
533533
}];
534534
}
535535

536+
- (void)getWaterSamples:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback
537+
{
538+
HKQuantityType *dietaryWaterType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryWater];
539+
HKUnit *literUnit = [HKUnit literUnit];
540+
NSUInteger limit = [RCTAppleHealthKit uintFromOptions:input key:@"limit" withDefault:HKObjectQueryNoLimit];
541+
BOOL ascending = [RCTAppleHealthKit boolFromOptions:input key:@"ascending" withDefault:false];
542+
NSDate *startDate = [RCTAppleHealthKit dateFromOptions:input key:@"startDate" withDefault:nil];
543+
NSDate *endDate = [RCTAppleHealthKit dateFromOptions:input key:@"endDate" withDefault:[NSDate date]];
544+
BOOL includeManuallyAdded = [RCTAppleHealthKit boolFromOptions:input key:@"includeManuallyAdded" withDefault:true];
545+
546+
547+
if(startDate == nil) {
548+
callback(@[RCTMakeError(@"startDate is required in options", nil, nil)]);
549+
return;
550+
}
551+
552+
NSPredicate * predicate = [RCTAppleHealthKit predicateForSamplesBetweenDates:startDate endDate:endDate];
553+
554+
[self fetchQuantitySamplesOfType:dietaryWaterType
555+
unit:literUnit
556+
predicate:predicate
557+
ascending:ascending
558+
limit:limit
559+
completion:^(NSArray *results, NSError *error) {
560+
if(results){
561+
callback(@[[NSNull null], results]);
562+
return;
563+
} else {
564+
NSLog(@"An error occured while retrieving the water sample %@. The error was: ", error);
565+
callback(@[RCTMakeError(@"An error occured while retrieving the water sample", error, nil)]);
566+
return;
567+
}
568+
}];
569+
}
570+
536571
@end

RCTAppleHealthKit/RCTAppleHealthKit+Methods_Fitness.m

+5-5
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ - (void)fitness_getStepCountOnDay:(NSDictionary *)input callback:(RCTResponseSen
3535
includeManuallyAdded:includeManuallyAdded
3636
day:date
3737
completion:^(double value, NSDate *startDate, NSDate *endDate, NSError *error) {
38-
if (!value && value != 0) {
38+
if ((!value && value != 0) || error != nil) {
3939
callback(@[RCTJSErrorFromNSError(error)]);
4040
return;
4141
}
@@ -218,7 +218,7 @@ - (void)fitness_getDistanceWalkingRunningOnDay:(NSDictionary *)input callback:(R
218218
HKQuantityType *quantityType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning];
219219

220220
[self fetchSumOfSamplesOnDayForType:quantityType unit:unit includeManuallyAdded:includeManuallyAdded day:date completion:^(double distance, NSDate *startDate, NSDate *endDate, NSError *error) {
221-
if (!distance && distance != 0) {
221+
if ((!distance && distance != 0) || error != nil) {
222222
callback(@[RCTJSErrorFromNSError(error)]);
223223
return;
224224
}
@@ -277,7 +277,7 @@ - (void)fitness_getDistanceSwimmingOnDay:(NSDictionary *)input callback:(RCTResp
277277
HKQuantityType *quantityType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceSwimming];
278278

279279
[self fetchSumOfSamplesOnDayForType:quantityType unit:unit includeManuallyAdded:includeManuallyAdded day:date completion:^(double distance, NSDate *startDate, NSDate *endDate, NSError *error) {
280-
if (!distance && distance != 0) {
280+
if ((!distance && distance != 0) || error != nil) {
281281
callback(@[RCTJSErrorFromNSError(error)]);
282282
return;
283283
}
@@ -334,7 +334,7 @@ - (void)fitness_getDistanceCyclingOnDay:(NSDictionary *)input callback:(RCTRespo
334334
HKQuantityType *quantityType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceCycling];
335335

336336
[self fetchSumOfSamplesOnDayForType:quantityType unit:unit includeManuallyAdded:includeManuallyAdded day:date completion:^(double distance, NSDate *startDate, NSDate *endDate, NSError *error) {
337-
if (!distance && distance != 0) {
337+
if ((!distance && distance != 0) || error != nil) {
338338
callback(@[RCTJSErrorFromNSError(error)]);
339339
return;
340340
}
@@ -391,7 +391,7 @@ - (void)fitness_getFlightsClimbedOnDay:(NSDictionary *)input callback:(RCTRespon
391391
HKQuantityType *quantityType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierFlightsClimbed];
392392

393393
[self fetchSumOfSamplesOnDayForType:quantityType unit:unit includeManuallyAdded:includeManuallyAdded day:date completion:^(double count, NSDate *startDate, NSDate *endDate, NSError *error) {
394-
if (!count && count != 0) {
394+
if ((!count && count != 0) || error != nil) {
395395
callback(@[RCTJSErrorFromNSError(error)]);
396396
return;
397397
}

RCTAppleHealthKit/RCTAppleHealthKit+Queries.m

+38-12
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ - (void)fetchSamplesOfType:(HKSampleType *)type
348348
@"activityName" : type,
349349
@"calories" : @(energy),
350350
@"tracked" : @(isTracked),
351-
@"metadata" : [sample metadata],
351+
@"metadata" : [sample metadata] ? [sample metadata] : [NSNull null],
352352
@"sourceName" : [[[sample sourceRevision] source] name],
353353
@"sourceId" : [[[sample sourceRevision] source] bundleIdentifier],
354354
@"device": device,
@@ -614,6 +614,21 @@ - (void)fetchSleepCategorySamplesForPredicate:(NSPredicate *)predicate
614614
case HKCategoryValueSleepAnalysisAsleep:
615615
valueString = @"ASLEEP";
616616
break;
617+
618+
// watchOS 9 and iOS 16 introduce Core, Deep, REM, and Awake phases of sleep.
619+
case HKCategoryValueSleepAnalysisAsleepCore:
620+
valueString = @"CORE";
621+
break;
622+
case HKCategoryValueSleepAnalysisAsleepDeep:
623+
valueString = @"DEEP";
624+
break;
625+
case HKCategoryValueSleepAnalysisAsleepREM:
626+
valueString = @"REM";
627+
break;
628+
case HKCategoryValueSleepAnalysisAwake:
629+
valueString = @"AWAKE";
630+
break;
631+
617632
default:
618633
valueString = @"UNKNOWN";
619634
break;
@@ -741,6 +756,12 @@ - (void)fetchSumOfSamplesOnDayForType:(HKQuantityType *)quantityType
741756
NSDate *startDate = result.startDate;
742757
NSDate *endDate = result.endDate;
743758
double value = [sum doubleValueForUnit:unit];
759+
if (startDate == nil || endDate == nil) {
760+
error = [[NSError alloc] initWithDomain:@"AppleHealthKit"
761+
code:0
762+
userInfo:@{@"Error reason": @"Could not fetch statistics: Not authorized"}
763+
];
764+
}
744765
completionHandler(value, startDate, endDate, error);
745766
}
746767
}];
@@ -1041,11 +1062,12 @@ - (void)setObserverForType:(HKSampleType *)sampleType
10411062
return;
10421063
}
10431064

1044-
[self sendEventWithName:successEvent body:@{}];
1065+
NSLog(@"Emitting event: %@", successEvent);
1066+
[self emitEventWithName:successEvent andPayload:@{}];
10451067

10461068
completionHandler();
10471069

1048-
NSLog(@"[HealthKit] New sample from Apple HealthKit processed - %@", type);
1070+
NSLog(@"[HealthKit] New sample from Apple HealthKit processed (dep) - %@ %@", type, successEvent);
10491071
}];
10501072

10511073

@@ -1062,7 +1084,7 @@ - (void)setObserverForType:(HKSampleType *)sampleType
10621084

10631085
[self.healthStore executeQuery:query];
10641086

1065-
[self sendEventWithName:successEvent body:@{}];
1087+
[self emitEventWithName:successEvent andPayload:@{}];
10661088
}];
10671089
}
10681090

@@ -1095,16 +1117,19 @@ - (void)setObserverForType:(HKSampleType *)sampleType
10951117

10961118
NSLog(@"[HealthKit] An error happened when receiving a new sample - %@", error.localizedDescription);
10971119
if(self.hasListeners) {
1098-
[self sendEventWithName:failureEvent body:@{}];
1120+
[self emitEventWithName:failureEvent andPayload:@{}];
10991121
}
11001122
return;
11011123
}
1124+
11021125
if(self.hasListeners) {
1103-
[self sendEventWithName:successEvent body:@{}];
1126+
[self emitEventWithName:successEvent andPayload:@{}];
1127+
} else {
1128+
NSLog(@"There is no listeners for %@", successEvent);
11041129
}
11051130
completionHandler();
11061131

1107-
NSLog(@"[HealthKit] New sample from Apple HealthKit processed - %@", type);
1132+
NSLog(@"[HealthKit] New sample from Apple HealthKit processed - %@ %@", type, successEvent);
11081133
}];
11091134

11101135

@@ -1117,15 +1142,16 @@ - (void)setObserverForType:(HKSampleType *)sampleType
11171142
if (error) {
11181143
NSLog(@"[HealthKit] An error happened when setting up background observer - %@", error.localizedDescription);
11191144
if(self.hasListeners) {
1120-
[self sendEventWithName:failureEvent body:@{}];
1145+
[self emitEventWithName:failureEvent andPayload:@{}];
11211146
}
11221147
return;
11231148
}
1124-
1149+
NSLog(@"[HealthKit] Background delivery enabled for %@", type);
11251150
[self.healthStore executeQuery:query];
1126-
if(self.hasListeners) {
1127-
[self sendEventWithName:successEvent body:@{}];
1128-
}
1151+
if(self.hasListeners) {
1152+
NSLog(@"[HealthKit] Background observer set up for %@", type);
1153+
[self emitEventWithName:successEvent andPayload:@{}];
1154+
}
11291155
}];
11301156
}
11311157

RCTAppleHealthKit/RCTAppleHealthKit+TypesAndPermissions.m

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ - (nullable HKObjectType *)getReadPermFromText:(nonnull NSString*)key {
2828
return [HKObjectType characteristicTypeForIdentifier:HKCharacteristicTypeIdentifierBiologicalSex];
2929
} else if ([@"BloodType" isEqualToString: key]) {
3030
return [HKObjectType characteristicTypeForIdentifier:HKCharacteristicTypeIdentifierBloodType];
31+
} else if ([@"PeakFlow" isEqualToString: key]) {
32+
return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierPeakExpiratoryFlowRate];
3133
} else if ([@"WaistCircumference" isEqualToString: key] && systemVersion >= 11.0) {
3234
return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierWaistCircumference];
3335
}
@@ -267,6 +269,8 @@ - (nullable HKObjectType *)getWritePermFromText:(nonnull NSString*) key {
267269
// Body Measurements
268270
if ([@"Height" isEqualToString:key]) {
269271
return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeight];
272+
} else if ([@"PeakFlow" isEqualToString: key]) {
273+
return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierPeakExpiratoryFlowRate];
270274
} else if ([@"WaistCircumference" isEqualToString:key]) {
271275
return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierWaistCircumference];
272276
} else if ([@"Weight" isEqualToString:key]) {

RCTAppleHealthKit/RCTAppleHealthKit+Utils.m

+3
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,9 @@ + (HKUnit *)hkUnitFromOptions:(NSDictionary *)options key:(NSString *)key withDe
293293
if ([unitString isEqualToString:@"mmolPerL"]) {
294294
theUnit = [[HKUnit moleUnitWithMetricPrefix:HKMetricPrefixMilli molarMass:HKUnitMolarMassBloodGlucose] unitDividedByUnit:[HKUnit literUnit]];
295295
}
296+
if ([unitString isEqualToString:@"literPerMinute"]) {
297+
theUnit = [[HKUnit literUnit] unitDividedByUnit:[HKUnit minuteUnit]];
298+
}
296299
if ([unitString isEqualToString:@"mgPerdL"]) {
297300
theUnit = [HKUnit unitFromString:@"mg/dL"];
298301
}

RCTAppleHealthKit/RCTAppleHealthKit.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
- (HKHealthStore *)_initializeHealthStore;
2424
- (void)isHealthKitAvailable:(RCTResponseSenderBlock)callback;
2525
- (void)initializeHealthKit:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback;
26-
- (void)checkPermission:(NSString *)input callback:(RCTResponseSenderBlock)callback;
2726
- (void)getModuleInfo:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback;
2827
- (void)getAuthorizationStatus:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback;
2928
- (void)initializeBackgroundObservers:(RCTBridge *)bridge;
29+
- (void)emitEventWithName:(NSString *)name andPayload:(NSDictionary *)payload;
3030

3131
@end

0 commit comments

Comments
 (0)