diff --git a/RCTAppleHealthKit.xcodeproj/project.pbxproj b/RCTAppleHealthKit.xcodeproj/project.pbxproj index 073f1be72c5026f28934346cdf5f86843470fcd2..b0dedf21a65c18cfa2fe7e082ec19d30aefe0cf6 100644 --- a/RCTAppleHealthKit.xcodeproj/project.pbxproj +++ b/RCTAppleHealthKit.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ 3774C8A11D20A6B90000B3F3 /* RCTAppleHealthKit+Utils.m in Sources */ = {isa = PBXBuildFile; fileRef = 3774C8A01D20A6B90000B3F3 /* RCTAppleHealthKit+Utils.m */; }; 3774C8D41D20C6390000B3F3 /* RCTAppleHealthKit+Methods_Body.m in Sources */ = {isa = PBXBuildFile; fileRef = 3774C8D31D20C6390000B3F3 /* RCTAppleHealthKit+Methods_Body.m */; }; 3774C8D71D20C65F0000B3F3 /* RCTAppleHealthKit+Methods_Fitness.m in Sources */ = {isa = PBXBuildFile; fileRef = 3774C8D61D20C65F0000B3F3 /* RCTAppleHealthKit+Methods_Fitness.m */; }; + 377D44F31D247D0A004E35CB /* RCTAppleHealthKit+Methods_Characteristic.m in Sources */ = {isa = PBXBuildFile; fileRef = 377D44F21D247D0A004E35CB /* RCTAppleHealthKit+Methods_Characteristic.m */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -43,6 +44,8 @@ 3774C8D31D20C6390000B3F3 /* RCTAppleHealthKit+Methods_Body.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTAppleHealthKit+Methods_Body.m"; sourceTree = ""; }; 3774C8D51D20C65F0000B3F3 /* RCTAppleHealthKit+Methods_Fitness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTAppleHealthKit+Methods_Fitness.h"; sourceTree = ""; }; 3774C8D61D20C65F0000B3F3 /* RCTAppleHealthKit+Methods_Fitness.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTAppleHealthKit+Methods_Fitness.m"; sourceTree = ""; }; + 377D44F11D247D0A004E35CB /* RCTAppleHealthKit+Methods_Characteristic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTAppleHealthKit+Methods_Characteristic.h"; sourceTree = ""; }; + 377D44F21D247D0A004E35CB /* RCTAppleHealthKit+Methods_Characteristic.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTAppleHealthKit+Methods_Characteristic.m"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -87,6 +90,8 @@ 3774C8D31D20C6390000B3F3 /* RCTAppleHealthKit+Methods_Body.m */, 3774C8D51D20C65F0000B3F3 /* RCTAppleHealthKit+Methods_Fitness.h */, 3774C8D61D20C65F0000B3F3 /* RCTAppleHealthKit+Methods_Fitness.m */, + 377D44F11D247D0A004E35CB /* RCTAppleHealthKit+Methods_Characteristic.h */, + 377D44F21D247D0A004E35CB /* RCTAppleHealthKit+Methods_Characteristic.m */, ); path = RCTAppleHealthKit; sourceTree = ""; @@ -151,6 +156,7 @@ 3774C8A11D20A6B90000B3F3 /* RCTAppleHealthKit+Utils.m in Sources */, 3774C8D41D20C6390000B3F3 /* RCTAppleHealthKit+Methods_Body.m in Sources */, 3774C8931D2092F20000B3F3 /* RCTAppleHealthKit.m in Sources */, + 377D44F31D247D0A004E35CB /* RCTAppleHealthKit+Methods_Characteristic.m in Sources */, 3774C89E1D2095850000B3F3 /* RCTAppleHealthKit+TypesAndPermissions.m in Sources */, 3774C8D71D20C65F0000B3F3 /* RCTAppleHealthKit+Methods_Fitness.m in Sources */, ); @@ -286,6 +292,7 @@ 3774C8981D2092F20000B3F3 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_Body.h b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_Body.h index 0503822855a4b007016ee2207483e09d2d812573..789bcc2574487758f606af4e778024ff8abc4c53 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_Body.h +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_Body.h @@ -11,15 +11,16 @@ @interface RCTAppleHealthKit (Methods_Body) - (void)body_getCurrentWeight:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback; +- (void)body_getWeightSamples:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback; - (void)body_saveWeight:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback; - (void)body_getLatestBodyMassIndex:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback; - (void)body_saveBodyMassIndex:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback; - (void)body_getMostRecentHeight:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback; +- (void)body_getHeightSamples:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback; - (void)body_saveHeight:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback; - - (void)body_getMostRecentBodyFatPercentage:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback; - (void)body_getMostRecentLeanBodyMass:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback; diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_Body.m b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_Body.m index 7cef81f32a81107d3302e948be534dee47c97e09..a2fcd516a0fb150148922c0c1e691c7c41475664 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_Body.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_Body.m @@ -37,16 +37,46 @@ } +- (void)body_getWeightSamples:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback +{ + HKQuantityType *weightType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass]; + + HKUnit *unit = [RCTAppleHealthKit hkUnitFromOptions:input key:@"unit" withDefault:[HKUnit poundUnit]]; + NSUInteger limit = [RCTAppleHealthKit uintFromOptions:input key:@"limit" withDefault:HKObjectQueryNoLimit]; + BOOL ascending = [RCTAppleHealthKit boolFromOptions:input key:@"ascending" withDefault:false]; + NSDate *startDate = [RCTAppleHealthKit dateFromOptions:input key:@"startDate" withDefault:nil]; + NSDate *endDate = [RCTAppleHealthKit dateFromOptions:input key:@"endDate" withDefault:[NSDate date]]; + if(startDate == nil){ + callback(@[RCTMakeError(@"startDate is required in options", nil, nil)]); + return; + } + NSPredicate * predicate = [RCTAppleHealthKit predicateForSamplesBetweenDates:startDate endDate:endDate]; + + [self fetchQuantitySamplesOfType:weightType + unit:unit + predicate:predicate + ascending:ascending + limit:limit + completion:^(NSArray *results, NSError *error) { + if(results){ + callback(@[[NSNull null], results]); + return; + } else { + NSLog(@"error getting weight samples: %@", error); + callback(@[RCTMakeError(@"error getting weight samples", nil, nil)]); + return; + } + }]; +} + + + + - (void)body_saveWeight:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback { -// double weight= [[input objectForKey:@"weight"] doubleValue]; double weight = [RCTAppleHealthKit doubleValueFromOptions:input]; NSDate *sampleDate = [RCTAppleHealthKit dateFromOptionsDefaultNow:input]; - - HKUnit *unit = [RCTAppleHealthKit hkUnitFromOptions:input]; - if(unit == nil){ - unit = [HKUnit poundUnit]; - } + HKUnit *unit = [RCTAppleHealthKit hkUnitFromOptions:input key:@"unit" withDefault:[HKUnit poundUnit]]; HKQuantity *weightQuantity = [HKQuantity quantityWithUnit:unit doubleValue:weight]; HKQuantityType *weightType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass]; @@ -136,6 +166,41 @@ } + +- (void)body_getHeightSamples:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback +{ + HKQuantityType *heightType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeight]; + + HKUnit *unit = [RCTAppleHealthKit hkUnitFromOptions:input key:@"unit" withDefault:[HKUnit inchUnit]]; + NSUInteger limit = [RCTAppleHealthKit uintFromOptions:input key:@"limit" withDefault:HKObjectQueryNoLimit]; + BOOL ascending = [RCTAppleHealthKit boolFromOptions:input key:@"ascending" withDefault:false]; + NSDate *startDate = [RCTAppleHealthKit dateFromOptions:input key:@"startDate" withDefault:nil]; + NSDate *endDate = [RCTAppleHealthKit dateFromOptions:input key:@"endDate" withDefault:[NSDate date]]; + if(startDate == nil){ + callback(@[RCTMakeError(@"startDate is required in options", nil, nil)]); + return; + } + NSPredicate * predicate = [RCTAppleHealthKit predicateForSamplesBetweenDates:startDate endDate:endDate]; + + [self fetchQuantitySamplesOfType:heightType + unit:unit + predicate:predicate + ascending:ascending + limit:limit + completion:^(NSArray *results, NSError *error) { + if(results){ + callback(@[[NSNull null], results]); + return; + } else { + NSLog(@"error getting height samples: %@", error); + callback(@[RCTMakeError(@"error getting height samples", nil, nil)]); + return; + } + }]; +} + + + - (void)body_saveHeight:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback { double height = [RCTAppleHealthKit doubleValueFromOptions:input]; diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_Characteristic.h b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_Characteristic.h new file mode 100644 index 0000000000000000000000000000000000000000..6c0adcceee71627374b47e04caa5ed5ec94abf0b --- /dev/null +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_Characteristic.h @@ -0,0 +1,16 @@ +// +// RCTAppleHealthKit+Methods_Characteristic.h +// RCTAppleHealthKit +// +// Created by Greg Wilson on 2016-06-29. +// Copyright © 2016 Greg Wilson. All rights reserved. +// + +#import "RCTAppleHealthKit.h" + +@interface RCTAppleHealthKit (Methods_Characteristic) + +- (void)characteristic_getBiologicalSex:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback; +- (void)characteristic_getDateOfBirth:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback; + +@end diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_Characteristic.m b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_Characteristic.m new file mode 100644 index 0000000000000000000000000000000000000000..a874c05d3fc0f28249e7fb6201b0daeba1665a51 --- /dev/null +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_Characteristic.m @@ -0,0 +1,62 @@ +// +// RCTAppleHealthKit+Methods_Characteristic.m +// RCTAppleHealthKit +// +// Created by Greg Wilson on 2016-06-29. +// Copyright © 2016 Greg Wilson. All rights reserved. +// + +#import "RCTAppleHealthKit+Methods_Characteristic.h" +#import "RCTAppleHealthKit+Utils.h" + +@implementation RCTAppleHealthKit (Methods_Characteristic) + + +- (void)characteristic_getBiologicalSex:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback { + NSError *error; + HKBiologicalSexObject *bioSex = [self.healthStore biologicalSexWithError:&error]; + NSString *value; + + switch (bioSex.biologicalSex) { + case HKBiologicalSexNotSet: + value = @"unknown"; + break; + case HKBiologicalSexFemale: + value = @"female"; + break; + case HKBiologicalSexMale: + value = @"male"; + break; + case HKBiologicalSexOther: + value = @"other"; + break; + } + + if(value == nil){ + NSLog(@"error getting biological sex: %@", error); + callback(@[RCTMakeError(@"error getting biological sex", error, nil)]); + return; + } + + callback(@[[NSNull null], value]); +} + + +- (void)characteristic_getDateOfBirth:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback { + NSError *error; + NSDate *dob = [self.healthStore dateOfBirthWithError:&error]; + + if(error != nil){ + NSLog(@"error getting date of birth: %@", error); + callback(@[RCTMakeError(@"error getting date of birth", error, nil)]); + return; + } + + NSString *dobString = [RCTAppleHealthKit buildISO8601StringFromDate:dob]; + + callback(@[[NSNull null], dobString]); +} + + + +@end diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Queries.h b/RCTAppleHealthKit/RCTAppleHealthKit+Queries.h index 608f961c8c573a1d1606056236bd40c170cc0e22..74b441e4d45d6be966c0707db0d57dbb8cb20787 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Queries.h +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Queries.h @@ -19,4 +19,14 @@ startDate:(NSDate *)startDate endDate:(NSDate *)endDate completion:(void (^)(NSArray *, NSError *))completionHandler; + + + +- (void)fetchQuantitySamplesOfType:(HKQuantityType *)quantityType + unit:(HKUnit *)unit + predicate:(NSPredicate *)predicate + ascending:(BOOL)asc + limit:(NSUInteger)lim + completion:(void (^)(NSArray *, NSError *))completion; + @end diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Queries.m b/RCTAppleHealthKit/RCTAppleHealthKit+Queries.m index 9ef010c056f46c9c099e861b9d66ec67162e3c91..6970b0cd4105c09d4fc38f90113c2bda7592d1b2 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Queries.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Queries.m @@ -12,8 +12,11 @@ @implementation RCTAppleHealthKit (Queries) -- (void)fetchMostRecentQuantitySampleOfType:(HKQuantityType *)quantityType predicate:(NSPredicate *)predicate completion:(void (^)(HKQuantity *, NSDate *, NSDate *, NSError *))completion { NSSortDescriptor *timeSortDescriptor = [[NSSortDescriptor alloc] initWithKey:HKSampleSortIdentifierEndDate ascending:NO]; +- (void)fetchMostRecentQuantitySampleOfType:(HKQuantityType *)quantityType + predicate:(NSPredicate *)predicate + completion:(void (^)(HKQuantity *, NSDate *, NSDate *, NSError *))completion { + NSSortDescriptor *timeSortDescriptor = [[NSSortDescriptor alloc] initWithKey:HKSampleSortIdentifierEndDate ascending:NO]; HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:quantityType predicate:predicate limit:1 @@ -41,6 +44,63 @@ +- (void)fetchQuantitySamplesOfType:(HKQuantityType *)quantityType + unit:(HKUnit *)unit + predicate:(NSPredicate *)predicate + ascending:(BOOL)asc + limit:(NSUInteger)lim + completion:(void (^)(NSArray *, NSError *))completion { + + NSSortDescriptor *timeSortDescriptor = [[NSSortDescriptor alloc] initWithKey:HKSampleSortIdentifierEndDate ascending:asc]; + HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:quantityType + predicate:predicate + limit:lim + sortDescriptors:@[timeSortDescriptor] + resultsHandler:^(HKSampleQuery *query, NSArray *results, NSError *error) { + + if (!results) { + if (completion) { + completion(nil, error); + } + return; + } + + if (completion) { + NSMutableArray *data = [NSMutableArray arrayWithCapacity:1]; + + dispatch_async(dispatch_get_main_queue(), ^{ + + for (HKQuantitySample *sample in results) { + HKQuantity *quantity = sample.quantity; +// NSDate *startDate = sample.startDate; +// NSDate *endDate = sample.endDate; + double value = [quantity doubleValueForUnit:unit]; + + NSString *startDateString = [RCTAppleHealthKit buildISO8601StringFromDate:sample.startDate]; + NSString *endDateString = [RCTAppleHealthKit buildISO8601StringFromDate:sample.endDate]; + + NSDictionary *elem = @{ + @"value" : @(value), + @"startDate" : startDateString, + @"endDate" : endDateString, + }; + + [data addObject:elem]; + } + + completion(data, error); + }); + } + + }]; + [self.healthStore executeQuery:query]; +} + + + + + + @@ -83,27 +143,6 @@ -//- (void)fetchSumOfSamplesBetweenDatesForType:(HKQuantityType *)quantityType unit:(HKUnit *)unit startDate:(NSDate *)startDate endDate:(NSDate *)endDate completion:(void (^)(NSArray *, NSError *))completionHandler { -// NSPredicate *predicate = [RCTAppleHealthKit predicateForSamplesBetweenDates:startDate endDate:endDate]; -// -// HKStatisticsQuery *query = [[HKStatisticsQuery alloc] initWithQuantityType:quantityType -// quantitySamplePredicate:predicate -// options:HKStatisticsOptionCumulativeSum -// completionHandler:^(HKStatisticsQuery *query, HKStatistics *result, NSError *error) { -// HKQuantity *sum = [result sumQuantity]; -// if (completionHandler) { -// double value = [sum doubleValueForUnit:unit]; -// completionHandler(value, error); -// } -// }]; -// -// [self.healthStore executeQuery:query]; -//} - - - - - - (void)fetchCumulativeSumStatisticsCollection:(HKQuantityType *)quantityType unit:(HKUnit *)unit startDate:(NSDate *)startDate @@ -119,30 +158,21 @@ fromDate:[NSDate date]]; anchorComponents.hour = 0; NSDate *anchorDate = [calendar dateFromComponents:anchorComponents]; -// HKQuantityType *quantityType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]; -// Create the query + // Create the query HKStatisticsCollectionQuery *query = [[HKStatisticsCollectionQuery alloc] initWithQuantityType:quantityType quantitySamplePredicate:nil options:HKStatisticsOptionCumulativeSum anchorDate:anchorDate intervalComponents:interval]; -// Set the results handler + // Set the results handler query.initialResultsHandler = ^(HKStatisticsCollectionQuery *query, HKStatisticsCollection *results, NSError *error) { if (error) { // Perform proper error handling here NSLog(@"*** An error occurred while calculating the statistics: %@ ***",error.localizedDescription); } -// NSDate *endDate = [NSDate date]; -// NSDate *startDate = [calendar dateByAddingUnit:NSCalendarUnitDay -// value:-7 -// toDate:endDate -// options:0]; - - // Plot the daily step counts over the past 7 days - NSMutableArray *data = [NSMutableArray arrayWithCapacity:1]; [results enumerateStatisticsFromDate:startDate diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Utils.h b/RCTAppleHealthKit/RCTAppleHealthKit+Utils.h index 3c44029b63633af9c56e2c58f4945f6014ff366f..c4aa7ebcf16b796204b56f463d7d66dcd24bad61 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Utils.h +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Utils.h @@ -24,4 +24,11 @@ + (NSDate *)endDateFromOptionsDefaultNow:(NSDictionary *)options; + (HKUnit *)hkUnitFromOptions:(NSDictionary *)options; ++ (HKUnit *)hkUnitFromOptions:(NSDictionary *)options key:(NSString *)key withDefault:(HKUnit *)defaultValue; ++ (NSUInteger)uintFromOptions:(NSDictionary *)options key:(NSString *)key withDefault:(NSUInteger)defaultValue; ++ (double)doubleFromOptions:(NSDictionary *)options key:(NSString *)key withDefault:(double)defaultValue; ++ (NSDate *)dateFromOptions:(NSDictionary *)options key:(NSString *)key withDefault:(NSDate *)defaultValue; ++ (NSString *)stringFromOptions:(NSDictionary *)options key:(NSString *)key withDefault:(NSString *)defaultValue; ++ (bool)boolFromOptions:(NSDictionary *)options key:(NSString *)key withDefault:(bool)defaultValue; + @end diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Utils.m b/RCTAppleHealthKit/RCTAppleHealthKit+Utils.m index 8191f960075ffa23fa4db80ad0dc8a1fbe166f8a..01005e7973ab3a9a1a798ec9c2ffa738535d080f 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Utils.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Utils.m @@ -60,6 +60,7 @@ + + (double)doubleValueFromOptions:(NSDictionary *)options { double value = [[options objectForKey:@"value"] doubleValue]; return value; @@ -174,6 +175,107 @@ } ++ (HKUnit *)hkUnitFromOptions:(NSDictionary *)options key:(NSString *)key withDefault:(HKUnit *)defaultValue { + NSString *unitString = [options objectForKey:key]; + HKUnit *theUnit; + + if([unitString isEqualToString:@"gram"]){ + theUnit = [HKUnit gramUnit]; + } + if([unitString isEqualToString:@"pound"]){ + theUnit = [HKUnit poundUnit]; + } + if([unitString isEqualToString:@"meter"]){ + theUnit = [HKUnit meterUnit]; + } + if([unitString isEqualToString:@"inch"]){ + theUnit = [HKUnit inchUnit]; + } + if([unitString isEqualToString:@"foot"]){ + theUnit = [HKUnit footUnit]; + } + if([unitString isEqualToString:@"second"]){ + theUnit = [HKUnit secondUnit]; + } + if([unitString isEqualToString:@"minute"]){ + theUnit = [HKUnit minuteUnit]; + } + if([unitString isEqualToString:@"hour"]){ + theUnit = [HKUnit hourUnit]; + } + if([unitString isEqualToString:@"day"]){ + theUnit = [HKUnit dayUnit]; + } + if([unitString isEqualToString:@"joule"]){ + theUnit = [HKUnit jouleUnit]; + } + if([unitString isEqualToString:@"calorie"]){ + theUnit = [HKUnit calorieUnit]; + } + if([unitString isEqualToString:@"count"]){ + theUnit = [HKUnit countUnit]; + } + if([unitString isEqualToString:@"percent"]){ + theUnit = [HKUnit percentUnit]; + } + + if(theUnit == nil){ + theUnit = defaultValue; + } + + return theUnit; +} + + ++ (NSUInteger)uintFromOptions:(NSDictionary *)options key:(NSString *)key withDefault:(NSUInteger)defaultValue { + NSUInteger val; + NSNumber *num = [options objectForKey:key]; + if(num != nil){ + val = [num unsignedIntValue]; + } else { + val = defaultValue; + } + return val; +} + ++ (double)doubleFromOptions:(NSDictionary *)options key:(NSString *)key withDefault:(double)defaultValue { + double val; + NSNumber *num = [options objectForKey:key]; + if(num != nil){ + val = [num doubleValue]; + } else { + val = defaultValue; + } + return val; +} + ++ (NSDate *)dateFromOptions:(NSDictionary *)options key:(NSString *)key withDefault:(NSDate *)defaultValue { + NSString *dateString = [options objectForKey:key]; + NSDate *date; + if(dateString != nil){ + date = [RCTAppleHealthKit parseISO8601DateFromString:dateString]; + } else { + date = defaultValue; + } + return date; +} + ++ (NSString *)stringFromOptions:(NSDictionary *)options key:(NSString *)key withDefault:(NSString *)defaultValue { + NSString *str = [options objectForKey:key]; + if(str == nil){ + str = defaultValue; + } + return str; +} + ++ (bool)boolFromOptions:(NSDictionary *)options key:(NSString *)key withDefault:(bool)defaultValue { + NSNumber *num = [options objectForKey:key]; + if(num == nil){ + return defaultValue; + } + return [num boolValue]; +} + @end diff --git a/RCTAppleHealthKit/RCTAppleHealthKit.m b/RCTAppleHealthKit/RCTAppleHealthKit.m index 210bd634889e8e878ca72df018a112f1dd63391b..a7705db03988b4e005b87e9304df02f2ad0f0aaf 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit.m @@ -13,6 +13,7 @@ #import "RCTAppleHealthKit+Methods_Body.h" #import "RCTAppleHealthKit+Methods_Fitness.h" +#import "RCTAppleHealthKit+Methods_Characteristic.h" @implementation RCTAppleHealthKit @@ -29,11 +30,26 @@ RCT_EXPORT_METHOD(initHealthKit:(NSDictionary *)input callback:(RCTResponseSende [self initializeHealthKit:input callback:callback]; } +RCT_EXPORT_METHOD(getBiologicalSex:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback) +{ + [self characteristic_getBiologicalSex:input callback:callback]; +} + +RCT_EXPORT_METHOD(getDateOfBirth:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback) +{ + [self characteristic_getDateOfBirth:input callback:callback]; +} + RCT_EXPORT_METHOD(getLatestWeight:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback) { [self body_getCurrentWeight:input callback:callback]; } +RCT_EXPORT_METHOD(getWeightSamples:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback) +{ + [self body_getWeightSamples:input callback:callback]; +} + RCT_EXPORT_METHOD(saveWeight:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback) { [self body_saveWeight:input callback:callback]; @@ -45,6 +61,11 @@ RCT_EXPORT_METHOD(getLatestHeight:(NSDictionary *)input callback:(RCTResponseSen [self body_getMostRecentHeight:input callback:callback]; } +RCT_EXPORT_METHOD(getHeightSamples:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback) +{ + [self body_getHeightSamples:input callback:callback]; +} + RCT_EXPORT_METHOD(saveHeight:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback) { [self body_saveHeight:input callback:callback]; diff --git a/examples/BodyMeasurements/app/stores/body.js b/examples/BodyMeasurements/app/stores/body.js index c69028d223452dc1cbfb3351b2a15dca8afba4db..7ffab822838df999a34e9d45261cd4acafd0a3fe 100644 --- a/examples/BodyMeasurements/app/stores/body.js +++ b/examples/BodyMeasurements/app/stores/body.js @@ -45,8 +45,12 @@ class BodyStore extends airflux.Store { //this.listenTo(actions.addWeight, this._onactn_addWeight) this._initHealthKit = this._initHealthKit.bind(this); + this._fetchHealthKitUserBiologicalSex = this._fetchHealthKitUserBiologicalSex.bind(this); + this._fetchHealthKitUserDateOfBirth = this._fetchHealthKitUserDateOfBirth.bind(this); this._fetchHealthKitUserWeight = this._fetchHealthKitUserWeight.bind(this); + this._fetchHealthKitUserWeightSamples = this._fetchHealthKitUserWeightSamples.bind(this); this._fetchHealthKitUserHeight = this._fetchHealthKitUserHeight.bind(this); + this._fetchHealthKitUserHeightSamples = this._fetchHealthKitUserHeightSamples.bind(this); this._fetchHealthKitUserBmi = this._fetchHealthKitUserBmi.bind(this); this._fetchHealthKitStepCountToday = this._fetchHealthKitStepCountToday.bind(this); this._fetchHealthKitStepCountForDay = this._fetchHealthKitStepCountForDay.bind(this); @@ -91,7 +95,7 @@ class BodyStore extends airflux.Store { let healthKitOptions = { permissions: { - read: ["Height", "Weight", "Steps", "DateOfBirth", "BodyMassIndex", "LeanBodyMass", "BodyFatPercentage"], + read: ["Height", "Weight", "Steps", "DateOfBirth", "BodyMassIndex", "LeanBodyMass", "BodyFatPercentage", "BiologicalSex"], write: ["Weight", "Height", "BodyMassIndex"] } }; @@ -112,6 +116,12 @@ class BodyStore extends airflux.Store { self._fetchHealthKitStepCountForDay(); self._fetchDailyStepCounts(); + self._fetchHealthKitUserWeightSamples(); + self._fetchHealthKitUserHeightSamples(); + + self._fetchHealthKitUserBiologicalSex(); + self._fetchHealthKitUserDateOfBirth(); + //setTimeout(() => {self._saveBmi(27)}, 1000); //setTimeout(() => {self._onactn_addWeight({ // weight: 215, @@ -155,6 +165,28 @@ class BodyStore extends airflux.Store { } + _fetchHealthKitUserBiologicalSex() { + let self = this; + AppleHealthKit.getBiologicalSex(null, (err, sex) => { + if(this._handleHealthKitError(err, 'getBiologicalSex')){ + return; + } + console.log('BiologicalSex: ', sex); + }); + } + + _fetchHealthKitUserDateOfBirth() { + let self = this; + AppleHealthKit.getDateOfBirth(null, (err, dob) => { + if(this._handleHealthKitError(err, 'getDateOfBirth')){ + return; + } + console.log('DateOfBirth: ', dob); + }); + } + + + _saveHeight(height_inches) { let self = this; let options = { @@ -197,6 +229,25 @@ class BodyStore extends airflux.Store { } + + _fetchHealthKitUserWeightSamples() { + let self = this; + let d = new Date(2016,4,27); + let options = { + unit: "pound", + startDate: d.toISOString(), + ascending: false, + limit:2, + }; + AppleHealthKit.getWeightSamples(options, (err, samples) => { + if(this._handleHealthKitError(err, 'getWeightSamples')){ + return; + } + console.log('weight samples: ', samples); + }); + } + + _fetchHealthKitUserHeight() { let self = this; let options = { @@ -220,6 +271,25 @@ class BodyStore extends airflux.Store { } + _fetchHealthKitUserHeightSamples() { + let self = this; + let d = new Date(2016,1,1); + let options = { + unit: "inch", + startDate: d.toISOString(), + //ascending: false, + //limit:2, + }; + AppleHealthKit.getHeightSamples(options, (err, samples) => { + if(this._handleHealthKitError(err, 'getHeightSamples')){ + return; + } + console.log('height samples: ', samples); + }); + } + + + _fetchHealthKitUserBmi() { let self = this; AppleHealthKit.getLatestBmi({blah:true}, (err, bmi) => { @@ -359,7 +429,7 @@ class BodyStore extends airflux.Store { GetHeightFormatted() { let feet = _.floor((DATA.height / 12)); - let inches = DATA.height % 12; + let inches = _.floor((DATA.height % 12)); let formatted = '' + feet + '\'' + inches + '"'; return formatted; } diff --git a/examples/BodyMeasurements/ios/BodyMeasurements.xcodeproj/project.pbxproj b/examples/BodyMeasurements/ios/BodyMeasurements.xcodeproj/project.pbxproj index 91857ab4230689e26614143d6a9bd4720a6e281d..b8174ab21aef2d7a7891cadf5fb5782dd1b7af3e 100644 --- a/examples/BodyMeasurements/ios/BodyMeasurements.xcodeproj/project.pbxproj +++ b/examples/BodyMeasurements/ios/BodyMeasurements.xcodeproj/project.pbxproj @@ -22,7 +22,7 @@ 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 140ED2AC1D01E1AD002B40FF /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; 146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; }; - 3787538F1D23661D0016D000 /* libRCTAppleHealthKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3787538E1D2366190016D000 /* libRCTAppleHealthKit.a */; }; + 377D44FA1D248091004E35CB /* libRCTAppleHealthKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 377D44F91D24808D004E35CB /* libRCTAppleHealthKit.a */; }; 37E9B8741D21B52F0090B19B /* HealthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 37E9B8731D21B52F0090B19B /* HealthKit.framework */; }; 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; /* End PBXBuildFile section */ @@ -91,9 +91,9 @@ remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192; remoteInfo = React; }; - 3787538D1D2366190016D000 /* PBXContainerItemProxy */ = { + 377D44F81D24808D004E35CB /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; - containerPortal = 378753891D2366190016D000 /* RCTAppleHealthKit.xcodeproj */; + containerPortal = 377D44F41D24808D004E35CB /* RCTAppleHealthKit.xcodeproj */; proxyType = 2; remoteGlobalIDString = 3774C88D1D2092F20000B3F3; remoteInfo = RCTAppleHealthKit; @@ -134,7 +134,7 @@ 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = BodyMeasurements/Info.plist; sourceTree = ""; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = BodyMeasurements/main.m; sourceTree = ""; }; 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = ""; }; - 378753891D2366190016D000 /* RCTAppleHealthKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAppleHealthKit.xcodeproj; path = "../node_modules/react-native-apple-healthkit/RCTAppleHealthKit.xcodeproj"; sourceTree = ""; }; + 377D44F41D24808D004E35CB /* RCTAppleHealthKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAppleHealthKit.xcodeproj; path = "../node_modules/react-native-apple-healthkit/RCTAppleHealthKit.xcodeproj"; sourceTree = ""; }; 37E9B8731D21B52F0090B19B /* HealthKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HealthKit.framework; path = System/Library/Frameworks/HealthKit.framework; sourceTree = SDKROOT; }; 37E9B8751D21B52F0090B19B /* BodyMeasurements.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = BodyMeasurements.entitlements; path = BodyMeasurements/BodyMeasurements.entitlements; sourceTree = ""; }; 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = ""; }; @@ -154,7 +154,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 3787538F1D23661D0016D000 /* libRCTAppleHealthKit.a in Frameworks */, + 377D44FA1D248091004E35CB /* libRCTAppleHealthKit.a in Frameworks */, 146834051AC3E58100842450 /* libReact.a in Frameworks */, 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */, 37E9B8741D21B52F0090B19B /* HealthKit.framework in Frameworks */, @@ -268,10 +268,10 @@ name = Products; sourceTree = ""; }; - 3787538A1D2366190016D000 /* Products */ = { + 377D44F51D24808D004E35CB /* Products */ = { isa = PBXGroup; children = ( - 3787538E1D2366190016D000 /* libRCTAppleHealthKit.a */, + 377D44F91D24808D004E35CB /* libRCTAppleHealthKit.a */, ); name = Products; sourceTree = ""; @@ -287,7 +287,7 @@ 832341AE1AAA6A7D00B99B32 /* Libraries */ = { isa = PBXGroup; children = ( - 378753891D2366190016D000 /* RCTAppleHealthKit.xcodeproj */, + 377D44F41D24808D004E35CB /* RCTAppleHealthKit.xcodeproj */, 146833FF1AC3E56700842450 /* React.xcodeproj */, 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */, 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */, @@ -411,8 +411,8 @@ ProjectRef = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */; }, { - ProductGroup = 3787538A1D2366190016D000 /* Products */; - ProjectRef = 378753891D2366190016D000 /* RCTAppleHealthKit.xcodeproj */; + ProductGroup = 377D44F51D24808D004E35CB /* Products */; + ProjectRef = 377D44F41D24808D004E35CB /* RCTAppleHealthKit.xcodeproj */; }, { ProductGroup = 00C302B61ABCB90400DB3ED1 /* Products */; @@ -516,11 +516,11 @@ remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 3787538E1D2366190016D000 /* libRCTAppleHealthKit.a */ = { + 377D44F91D24808D004E35CB /* libRCTAppleHealthKit.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; path = libRCTAppleHealthKit.a; - remoteRef = 3787538D1D2366190016D000 /* PBXContainerItemProxy */; + remoteRef = 377D44F81D24808D004E35CB /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; 78C398B91ACF4ADC00677621 /* libRCTLinking.a */ = {