From 1f065d12dab3df45130684d1058701b54f081864 Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Wed, 15 Mar 2023 16:46:53 +0300 Subject: [PATCH 01/31] getMedianStatistic added --- RCTAppleHealthKit.xcodeproj/project.pbxproj | 6 ++ .../xcschemes/RCTAppleHealthKit.xcscheme | 67 +++++++++++++++++++ ...CAppleHealthKit_Methods_MedianStatistics.h | 15 +++++ ...CAppleHealthKit_Methods_MedianStatistics.m | 50 ++++++++++++++ RCTAppleHealthKit/RCTAppleHealthKit.m | 7 ++ 5 files changed, 145 insertions(+) create mode 100644 RCTAppleHealthKit.xcodeproj/xcshareddata/xcschemes/RCTAppleHealthKit.xcscheme create mode 100644 RCTAppleHealthKit/RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.h create mode 100644 RCTAppleHealthKit/RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.m diff --git a/RCTAppleHealthKit.xcodeproj/project.pbxproj b/RCTAppleHealthKit.xcodeproj/project.pbxproj index 2339c7e9..900fb5c7 100644 --- a/RCTAppleHealthKit.xcodeproj/project.pbxproj +++ b/RCTAppleHealthKit.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ 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 */; }; 37837E7D1DCFE270000201A0 /* RCTAppleHealthKit+Methods_Sleep.m in Sources */ = {isa = PBXBuildFile; fileRef = 37837E7C1DCFE270000201A0 /* RCTAppleHealthKit+Methods_Sleep.m */; }; + 40CA05B029C08A07005C8255 /* RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.m in Sources */ = {isa = PBXBuildFile; fileRef = 40CA05AF29C08A07005C8255 /* RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.m */; }; 4F8095C92523C39D00A84ADB /* RCTAppleHealthKit+Methods_LabTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F8095C82523C39D00A84ADB /* RCTAppleHealthKit+Methods_LabTests.m */; }; 58C81E6F1F84F6970005DD48 /* RCTAppleHealthKit+Methods_Activity.m in Sources */ = {isa = PBXBuildFile; fileRef = 58C81E6D1F84F6970005DD48 /* RCTAppleHealthKit+Methods_Activity.m */; }; 61232F931E303758000A5026 /* RCTAppleHealthKit+Methods_Mindfulness.m in Sources */ = {isa = PBXBuildFile; fileRef = 61232F921E303758000A5026 /* RCTAppleHealthKit+Methods_Mindfulness.m */; }; @@ -66,6 +67,8 @@ 377D44F21D247D0A004E35CB /* RCTAppleHealthKit+Methods_Characteristic.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTAppleHealthKit+Methods_Characteristic.m"; sourceTree = ""; }; 37837E7B1DCFE270000201A0 /* RCTAppleHealthKit+Methods_Sleep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTAppleHealthKit+Methods_Sleep.h"; sourceTree = ""; }; 37837E7C1DCFE270000201A0 /* RCTAppleHealthKit+Methods_Sleep.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTAppleHealthKit+Methods_Sleep.m"; sourceTree = ""; }; + 40CA05AE29C08A07005C8255 /* RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.h"; sourceTree = ""; }; + 40CA05AF29C08A07005C8255 /* RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.m"; sourceTree = ""; }; 4F8095C72523C39D00A84ADB /* RCTAppleHealthKit+Methods_LabTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTAppleHealthKit+Methods_LabTests.h"; sourceTree = ""; }; 4F8095C82523C39D00A84ADB /* RCTAppleHealthKit+Methods_LabTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTAppleHealthKit+Methods_LabTests.m"; sourceTree = ""; }; 58C81E6D1F84F6970005DD48 /* RCTAppleHealthKit+Methods_Activity.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "RCTAppleHealthKit+Methods_Activity.m"; sourceTree = ""; }; @@ -154,6 +157,8 @@ 8C79D95F268E081A00DBDC40 /* RCTAppleHealthKit+Methods_ClinicalRecords.m */, 136368C1272BE98800C9A95F /* RTCAppleHealthKit+Methods_Statistics.h */, 136368C2272BE98800C9A95F /* RTCAppleHealthKit+Methods_Statistics.m */, + 40CA05AE29C08A07005C8255 /* RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.h */, + 40CA05AF29C08A07005C8255 /* RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.m */, ABA7B427B5187820CBE7BCD1 /* Types */, ABA7B06B86046F15D272E16A /* RCTTypes.h */, ); @@ -242,6 +247,7 @@ 3774C8931D2092F20000B3F3 /* RCTAppleHealthKit.m in Sources */, 377D44F31D247D0A004E35CB /* RCTAppleHealthKit+Methods_Characteristic.m in Sources */, 4F8095C92523C39D00A84ADB /* RCTAppleHealthKit+Methods_LabTests.m in Sources */, + 40CA05B029C08A07005C8255 /* RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.m in Sources */, 3774C89E1D2095850000B3F3 /* RCTAppleHealthKit+TypesAndPermissions.m in Sources */, 3774C8D71D20C65F0000B3F3 /* RCTAppleHealthKit+Methods_Fitness.m in Sources */, 58C81E6F1F84F6970005DD48 /* RCTAppleHealthKit+Methods_Activity.m in Sources */, diff --git a/RCTAppleHealthKit.xcodeproj/xcshareddata/xcschemes/RCTAppleHealthKit.xcscheme b/RCTAppleHealthKit.xcodeproj/xcshareddata/xcschemes/RCTAppleHealthKit.xcscheme new file mode 100644 index 00000000..6ed10c11 --- /dev/null +++ b/RCTAppleHealthKit.xcodeproj/xcshareddata/xcschemes/RCTAppleHealthKit.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.h b/RCTAppleHealthKit/RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.h new file mode 100644 index 00000000..0716e198 --- /dev/null +++ b/RCTAppleHealthKit/RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.h @@ -0,0 +1,15 @@ +// +// RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.h +// RCTAppleHealthKit +// +// Created by Anastasia Mishur on 14.03.23. +// Copyright © 2023 Greg Wilson. All rights reserved. +// + +#import "RCTAppleHealthKit.h" + +@interface RCTAppleHealthKit (RTCAppleHealthKit_Methods_MedianStatistics) + +- (void)statistics_getMedianStatistic:(NSArray *)input callback:(RCTResponseSenderBlock)callback; + +@end diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.m b/RCTAppleHealthKit/RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.m new file mode 100644 index 00000000..1f530b59 --- /dev/null +++ b/RCTAppleHealthKit/RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.m @@ -0,0 +1,50 @@ +// +// RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.m +// RCTAppleHealthKit +// +// Created by Anastasia Mishur on 14.03.23. +// Copyright © 2023 Greg Wilson. All rights reserved. +// + +#import "RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.h" +#import "RCTAppleHealthKit+Queries.h" +#import "RCTAppleHealthKit+Utils.h" +#import "RCTAppleHealthKit+TypesAndPermissions.h" +#import "RTCAppleHealthKit+Methods_Statistics.h" + +#import + +@implementation RCTAppleHealthKit (RTCAppleHealthKit_Methods_MedianStatistics) + +// MARK: - Public + +- (void)statistics_getMedianStatistic:(NSArray *)input callback:(RCTResponseSenderBlock)callback { + + NSLog(@"Have input:", input.firstObject, input); + + + //fake callback + NSMutableArray* output = [NSMutableArray new]; + NSDictionary *response1 = @{ + @"parameter" : @"weight", + @"firstEntry" : @"first date", + @"lastEntry" : @"last date", + @"entryCount" : @23, + @"medianDays" : @4, + }; + [output addObject:response1]; + + NSDictionary *response2 = @{ + @"parameter" : @"height", + @"firstEntry" : @"first date", + @"lastEntry" : @"last date", + @"entryCount" : @15, + @"medianDays" : @2, + }; + [output addObject:response2]; + + callback(@[[NSNull null], output]); + +} + +@end diff --git a/RCTAppleHealthKit/RCTAppleHealthKit.m b/RCTAppleHealthKit/RCTAppleHealthKit.m index 6452a106..98f32f4f 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit.m @@ -24,6 +24,7 @@ #import "RCTAppleHealthKit+Methods_Summary.h" #import "RCTAppleHealthKit+Methods_ClinicalRecords.h" #import "RTCAppleHealthKit+Methods_Statistics.h" +#import "RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.h" #import #import @@ -594,6 +595,12 @@ + (BOOL)requiresMainQueueSetup [self statistics_getStatisticRestingHeartRate:input callback:callback]; } +RCT_EXPORT_METHOD(getMedianStatistic:(NSArray *)input callback:(RCTResponseSenderBlock)callback) +{ + [self _initializeHealthStore]; + [self statistics_getMedianStatistic:input callback:callback]; +} + - (HKHealthStore *)_initializeHealthStore { if(![self healthStore]) { self.healthStore = [[HKHealthStore alloc] init]; From bd2befd0d3254af22b1d96c00304e13b778e9e8a Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Wed, 15 Mar 2023 17:06:06 +0300 Subject: [PATCH 02/31] Update RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.m --- ...TAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.m b/RCTAppleHealthKit/RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.m index 1f530b59..54fde51c 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.m @@ -20,7 +20,7 @@ @implementation RCTAppleHealthKit (RTCAppleHealthKit_Methods_MedianStatistics) - (void)statistics_getMedianStatistic:(NSArray *)input callback:(RCTResponseSenderBlock)callback { - NSLog(@"Have input:", input.firstObject, input); + NSLog(@"Have input: first element is - %@", input.firstObject); //fake callback From d21f3bd96691482dee63364b99913e106671c8d1 Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Mon, 20 Mar 2023 21:57:38 +0300 Subject: [PATCH 03/31] Utils extended with new methods --- RCTAppleHealthKit/RCTAppleHealthKit+Utils.h | 4 ++ RCTAppleHealthKit/RCTAppleHealthKit+Utils.m | 57 +++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Utils.h b/RCTAppleHealthKit/RCTAppleHealthKit+Utils.h index 961cbc1e..b49855f5 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Utils.h +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Utils.h @@ -47,5 +47,9 @@ extern NSString * const kMetadataKey; + (NSString *) md5HashString:(NSString *) input; + (NSString *) stringFromObject:(NSObject *)obj; + (NSString *) formattingStringHash:(NSString *)input; ++ (NSNumber *) calculateMedian:(NSArray *)input; ++ (NSInteger) daysFromSeconds:(NSDate *)startDate endDate: (NSDate *)endDate; ++ (HKSample *) firstByDateFromSamples:(NSArray<__kindof HKSample *>*)input; ++ (HKSample *) lastByDateFromSamples:(NSArray<__kindof HKSample *>*)input; @end diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Utils.m b/RCTAppleHealthKit/RCTAppleHealthKit+Utils.m index 794bc2ba..66ac3a5b 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Utils.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Utils.m @@ -658,4 +658,61 @@ + (NSString *)formattingStringHash:(NSString *)input { return result.uppercaseString; } ++ (NSNumber *)calculateMedian:(NSArray *)input { + if (input.count == 0) { + return nil; + } + + NSArray *sorted = [input sortedArrayUsingSelector:@selector(compare:)]; + + if ((sorted.count % 2) == 0) { + NSInteger middleLeftIndex = (sorted.count / 2); + NSInteger middleRightIndex = (sorted.count / 2) - 1; + + NSNumber *median = @(([sorted[middleLeftIndex] integerValue] + [sorted[middleRightIndex] integerValue]) / 2); + return median; + } else { + NSNumber *median = sorted[(sorted.count - 1) / 2]; + return median; + } +} + ++ (NSInteger)daysFromSeconds:(NSDate *)startDate endDate: (NSDate *)endDate { + NSCalendar *gregorian = [[NSCalendar alloc] + initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; + + NSUInteger unitFlags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay; + NSDateComponents *components = [gregorian components:unitFlags + fromDate:startDate + toDate:endDate + options:0]; + NSInteger days = fabs([components day]); + return days; +} + ++ (HKSample *)firstByDateFromSamples:(NSArray<__kindof HKSample *>*)input { + + NSSortDescriptor *dateDescriptor = [NSSortDescriptor + sortDescriptorWithKey:@"startDate" + ascending:YES]; + NSArray *sortDescriptors = [NSArray arrayWithObject:dateDescriptor]; + NSArray *sorted = [input + sortedArrayUsingDescriptors:sortDescriptors]; + + return sorted.firstObject; +} + ++ (HKSample *)lastByDateFromSamples:(NSArray<__kindof HKSample *>*)input { + + NSSortDescriptor *dateDescriptor = [NSSortDescriptor + sortDescriptorWithKey:@"endDate" + ascending:YES]; + NSArray *sortDescriptors = [NSArray arrayWithObject:dateDescriptor]; + NSArray *sorted = [input + sortedArrayUsingDescriptors:sortDescriptors]; + + return sorted.lastObject; +} + + @end From 8620ea143628aa4a7e0e261a9fb3fd57aec5bd90 Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Mon, 20 Mar 2023 21:58:32 +0300 Subject: [PATCH 04/31] getReadPermFromText changed availability to public --- RCTAppleHealthKit/RCTAppleHealthKit+TypesAndPermissions.h | 1 + 1 file changed, 1 insertion(+) diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+TypesAndPermissions.h b/RCTAppleHealthKit/RCTAppleHealthKit+TypesAndPermissions.h index 4d0dd037..36c16ae9 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+TypesAndPermissions.h +++ b/RCTAppleHealthKit/RCTAppleHealthKit+TypesAndPermissions.h @@ -13,6 +13,7 @@ - (NSDictionary *)readPermsDict; - (NSDictionary *)writePermsDict; - (NSSet *)getReadPermsFromOptions:(NSArray *)options; +- (nullable HKObjectType *)getReadPermFromText:(nonnull NSString*)key; - (NSSet *)getWritePermsFromOptions:(NSArray *)options; - (HKObjectType *)getWritePermFromString:(NSString *)string; - (NSString *)getAuthorizationStatusString:(HKAuthorizationStatus)status; From 601579443860029ab1a9b2f4f24ee3ac582da164 Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Mon, 20 Mar 2023 22:02:29 +0300 Subject: [PATCH 05/31] fetchBatchOfSamples query method added --- RCTAppleHealthKit/RCTAppleHealthKit+Queries.h | 5 ++++ RCTAppleHealthKit/RCTAppleHealthKit+Queries.m | 29 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Queries.h b/RCTAppleHealthKit/RCTAppleHealthKit+Queries.h index 4ae52855..64dcfeb4 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Queries.h +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Queries.h @@ -120,5 +120,10 @@ ascending:(BOOL)asc limit:(NSUInteger)lim completion:(void (^)(NSArray *, NSError *))completion; +- (void)fetchBatchOfSamples:(HKSampleType *)type + predicate:(NSPredicate *)predicate + anchor:(HKQueryAnchor *)anchor + limit:(NSUInteger)lim + completion:(void (^)(NSDictionary *, NSError *))completion; @end diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Queries.m b/RCTAppleHealthKit/RCTAppleHealthKit+Queries.m index 33220d84..4d63f7ef 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Queries.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Queries.m @@ -1171,4 +1171,33 @@ - (void)fetchStatisticsSamplesOfType:(HKQuantityType *)quantityType [self.healthStore executeQuery:query]; } +- (void)fetchBatchOfSamples:(HKSampleType *)type + predicate:(NSPredicate *)predicate + anchor:(HKQueryAnchor *)anchor + limit:(NSUInteger)lim + completion:(void (^)(NSDictionary *, NSError *))completion { + + // declare the block + void (^handlerBlock)(HKAnchoredObjectQuery *query, NSArray<__kindof HKSample *> *sampleObjects, NSArray *deletedObjects, HKQueryAnchor *newAnchor, NSError *error); + + // create and assign the block + handlerBlock = ^(HKAnchoredObjectQuery *query, NSArray<__kindof HKSample *> *sampleObjects, NSArray *deletedObjects, HKQueryAnchor *newAnchor, NSError *error) { + if (completion) { + NSData *anchorData = [NSKeyedArchiver archivedDataWithRootObject:newAnchor]; + NSString *anchorString = [anchorData base64EncodedStringWithOptions:0]; + completion(@{ + @"anchor": anchorString, + @"data": sampleObjects, + }, error); + } + }; + HKAnchoredObjectQuery *query = [[HKAnchoredObjectQuery alloc] initWithType:type + predicate:predicate + anchor:anchor + limit:lim + resultsHandler:handlerBlock]; + + [self.healthStore executeQuery:query]; +} + @end From d499b7333ddbd1b206110c8a090363c3ec6872c2 Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Tue, 21 Mar 2023 23:49:09 +0300 Subject: [PATCH 06/31] Update RCTAppleHealthKit+Queries.m --- RCTAppleHealthKit/RCTAppleHealthKit+Queries.m | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Queries.m b/RCTAppleHealthKit/RCTAppleHealthKit+Queries.m index 4d63f7ef..484b202f 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Queries.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Queries.m @@ -1182,14 +1182,27 @@ - (void)fetchBatchOfSamples:(HKSampleType *)type // create and assign the block handlerBlock = ^(HKAnchoredObjectQuery *query, NSArray<__kindof HKSample *> *sampleObjects, NSArray *deletedObjects, HKQueryAnchor *newAnchor, NSError *error) { - if (completion) { - NSData *anchorData = [NSKeyedArchiver archivedDataWithRootObject:newAnchor]; - NSString *anchorString = [anchorData base64EncodedStringWithOptions:0]; - completion(@{ - @"anchor": anchorString, - @"data": sampleObjects, - }, error); - } + + dispatch_async(dispatch_get_main_queue(), ^{ + + if (error) { + if (completion) { + completion(nil, error); + } + return; + } + + if (completion) { + + NSData *anchorData = [NSKeyedArchiver archivedDataWithRootObject:newAnchor]; + NSString *anchorString = [anchorData base64EncodedStringWithOptions:0]; + + completion(@{ + @"anchor": anchorString, + @"data": sampleObjects, + }, error); + } + }); }; HKAnchoredObjectQuery *query = [[HKAnchoredObjectQuery alloc] initWithType:type predicate:predicate From 02c5c54cd0f8e60d13a4c7712eaaf6938cd7076e Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Wed, 22 Mar 2023 16:44:24 +0300 Subject: [PATCH 07/31] renaming --- RCTAppleHealthKit/RCTAppleHealthKit.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RCTAppleHealthKit/RCTAppleHealthKit.m b/RCTAppleHealthKit/RCTAppleHealthKit.m index 98f32f4f..5885758c 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit.m @@ -24,7 +24,7 @@ #import "RCTAppleHealthKit+Methods_Summary.h" #import "RCTAppleHealthKit+Methods_ClinicalRecords.h" #import "RTCAppleHealthKit+Methods_Statistics.h" -#import "RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.h" +#import "RCTAppleHealthKit+Methods_MedianStatistics.h" #import #import From 539d5a410f8e78e83151a874940c291bb2c99972 Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Wed, 22 Mar 2023 16:44:32 +0300 Subject: [PATCH 08/31] Update RCTAppleHealthKit+Queries.m --- RCTAppleHealthKit/RCTAppleHealthKit+Queries.m | 1 + 1 file changed, 1 insertion(+) diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Queries.m b/RCTAppleHealthKit/RCTAppleHealthKit+Queries.m index 484b202f..ab60bddb 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Queries.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Queries.m @@ -1186,6 +1186,7 @@ - (void)fetchBatchOfSamples:(HKSampleType *)type dispatch_async(dispatch_get_main_queue(), ^{ if (error) { + NSLog(@"RNHealth: An error occured for %@: %@", type.description, error.description); if (completion) { completion(nil, error); } From b18de5d8c8f458c9fb7bb92a18f88e9b50a8a903 Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Wed, 22 Mar 2023 22:41:59 +0300 Subject: [PATCH 09/31] TypesForMedianStatistic added --- ...CTAppleHealthKit+TypesForMedianStatistic.h | 14 ++ ...CTAppleHealthKit+TypesForMedianStatistic.m | 150 ++++++++++++++++++ 2 files changed, 164 insertions(+) create mode 100644 RCTAppleHealthKit/RCTAppleHealthKit+TypesForMedianStatistic.h create mode 100644 RCTAppleHealthKit/RCTAppleHealthKit+TypesForMedianStatistic.m diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+TypesForMedianStatistic.h b/RCTAppleHealthKit/RCTAppleHealthKit+TypesForMedianStatistic.h new file mode 100644 index 00000000..681264cc --- /dev/null +++ b/RCTAppleHealthKit/RCTAppleHealthKit+TypesForMedianStatistic.h @@ -0,0 +1,14 @@ +// +// RCTAppleHealthKit+TypesForMedianStatistic.h +// RNAppleHealthKit +// +// Created by Anastasia Mishur on 22.03.23. +// + +#import "RCTAppleHealthKit.h" + +@interface RCTAppleHealthKit (TypesForMedianStatistic) + +- (nullable HKSampleType *)getObjectFromText:(nonnull NSString*)key; + +@end diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+TypesForMedianStatistic.m b/RCTAppleHealthKit/RCTAppleHealthKit+TypesForMedianStatistic.m new file mode 100644 index 00000000..b933bbd6 --- /dev/null +++ b/RCTAppleHealthKit/RCTAppleHealthKit+TypesForMedianStatistic.m @@ -0,0 +1,150 @@ +// +// RCTAppleHealthKit+TypesForMedianStatistic.m +// RNAppleHealthKit +// +// Created by Anastasia Mishur on 22.03.23. +// + +#import "RCTAppleHealthKit+TypesForMedianStatistic.h" +#import "RCTAppleHealthKit+TypesAndPermissions.h" + +@implementation RCTAppleHealthKit (TypesForMedianStatistic) + +- (nullable HKSampleType *)getObjectFromText:(nonnull NSString*)key { + HKSampleType * _Nullable sample = (HKSampleType *)[self getReadPermFromText:key]; + if (sample != nil) { + return sample; + } else { + HKSampleType * _Nullable workoutObject = (HKSampleType *)[self getObjectForActivityType:key]; + return workoutObject; + } +} + +- (nullable HKObjectType *)getObjectForActivityType:(nonnull NSString*)key { + UIDevice *deviceInfo = [UIDevice currentDevice]; + float systemVersion = deviceInfo.systemVersion.floatValue; + + // documented lower iOS version + if (systemVersion < 8.0) { + return nil; + } + + if ([@"AmericanFootball" isEqualToString: key] || + [@"Archery" isEqualToString: key] || + [@"AustralianFootball" isEqualToString: key] || + [@"Badminton" isEqualToString: key] || + [@"Baseball" isEqualToString: key] || + [@"Basketball" isEqualToString: key] || + [@"Bowling" isEqualToString: key] || + [@"Boxing" isEqualToString: key] || + [@"Climbing" isEqualToString: key] || + [@"Cricket" isEqualToString: key] || + [@"CrossTraining" isEqualToString: key] || + [@"Curling" isEqualToString: key] || + [@"Cycling" isEqualToString: key] || + [@"Elliptical" isEqualToString: key] || + [@"EquestrianSports" isEqualToString: key] || + [@"Fencing" isEqualToString: key] || + [@"Fishing" isEqualToString: key] || + [@"FunctionalStrengthTraining" isEqualToString: key] || + [@"Golf" isEqualToString: key] || + [@"Gymnastics" isEqualToString: key] || + [@"Handball" isEqualToString: key] || + [@"Hiking" isEqualToString: key] || + [@"Hockey" isEqualToString: key] || + [@"Hunting" isEqualToString: key] || + [@"Lacrosse" isEqualToString: key] || + [@"MartialArts" isEqualToString: key] || + [@"MindAndBody" isEqualToString: key] || + [@"PaddleSports" isEqualToString: key] || + [@"Play" isEqualToString: key] || + [@"PreparationAndRecovery" isEqualToString: key] || + [@"Racquetball" isEqualToString: key] || + [@"Rowing" isEqualToString: key] || + [@"Rugby" isEqualToString: key] || + [@"Running" isEqualToString: key] || + [@"Sailing" isEqualToString: key] || + [@"SkatingSports" isEqualToString: key] || + [@"SnowSports" isEqualToString: key] || + [@"Soccer" isEqualToString: key] || + [@"Softball" isEqualToString: key] || + [@"Squash" isEqualToString: key] || + [@"StairClimbing" isEqualToString: key] || + [@"SurfingSports" isEqualToString: key] || + [@"Swimming" isEqualToString: key] || + [@"TableTennis" isEqualToString: key] || + [@"Tennis" isEqualToString: key] || + [@"TrackAndField" isEqualToString: key] || + [@"TraditionalStrengthTraining" isEqualToString: key] || + [@"Volleyball" isEqualToString: key] || + [@"Walking" isEqualToString: key] || + [@"WaterFitness" isEqualToString: key] || + [@"WaterPolo" isEqualToString: key] || + [@"WaterSports" isEqualToString: key] || + [@"Wrestling" isEqualToString: key] || + [@"Yoga" isEqualToString: key]) { + return [HKObjectType workoutType]; + } + + if ([@"Barre" isEqualToString: key] && systemVersion >= 10.0) { + return [HKObjectType workoutType]; + } else if ([@"CoreTraining" isEqualToString: key] && systemVersion >= 10.0) { + return [HKObjectType workoutType]; + } else if ([@"CrossCountrySkiing" isEqualToString: key] && systemVersion >= 10.0) { + return [HKObjectType workoutType]; + } else if ([@"DownhillSkiing" isEqualToString: key] && systemVersion >= 10.0) { + return [HKObjectType workoutType]; + } else if ([@"Flexibility" isEqualToString: key] && systemVersion >= 10.0) { + return [HKObjectType workoutType]; + } else if ([@"HighIntensityIntervalTraining" isEqualToString: key] && systemVersion >= 10.0) { + return [HKObjectType workoutType]; + } else if ([@"JumpRope" isEqualToString: key] && systemVersion >= 10.0) { + return [HKObjectType workoutType]; + } else if ([@"Kickboxing" isEqualToString: key] && systemVersion >= 10.0) { + return [HKObjectType workoutType]; + } else if ([@"Pilates" isEqualToString: key] && systemVersion >= 10.0) { + return [HKObjectType workoutType]; + } else if ([@"Snowboarding" isEqualToString: key] && systemVersion >= 10.0) { + return [HKObjectType workoutType]; + } else if ([@"Stairs" isEqualToString: key] && systemVersion >= 10.0) { + return [HKObjectType workoutType]; + } else if ([@"StepTraining" isEqualToString: key] && systemVersion >= 10.0) { + return [HKObjectType workoutType]; + } else if ([@"WheelchairWalkPace" isEqualToString: key] && systemVersion >= 10.0) { + return [HKObjectType workoutType]; + } else if ([@"WheelchairRunPace" isEqualToString: key] && systemVersion >= 10.0) { + return [HKObjectType workoutType]; + } + + if ([@"TaiChi" isEqualToString: key] && systemVersion >= 11.0) { + return [HKObjectType workoutType]; + } else if ([@"MixedCardio" isEqualToString: key] && systemVersion >= 11.0) { + return [HKObjectType workoutType]; + } else if ([@"HandCycling" isEqualToString: key] && systemVersion >= 11.0) { + return [HKObjectType workoutType]; + } + + if ([@"DiscSports" isEqualToString: key] && systemVersion >= 13.0) { + return [HKObjectType workoutType]; + } else if ([@"FitnessGaming" isEqualToString: key] && systemVersion >= 13.0) { + return [HKObjectType workoutType]; + } + + if ([@"CardioDance" isEqualToString: key] && systemVersion >= 14.0) { + return [HKObjectType workoutType]; + } else if ([@"Cooldown" isEqualToString: key] && systemVersion >= 14.0) { + return [HKObjectType workoutType]; + } else if ([@"Pickleball" isEqualToString: key] && systemVersion >= 14.0) { + return [HKObjectType workoutType]; + } else if ([@"SocialDance" isEqualToString: key] && systemVersion >= 14.0) { + return [HKObjectType workoutType]; + } + + if ([@"HKWorkoutActivityTypeSwimBikeRun" isEqualToString: key] && systemVersion >= 16.0) { + return [HKObjectType workoutType]; + } + + return nil; +} + +@end From 3c07444f2f122078aa9cf482421d4d07fa539437 Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Wed, 22 Mar 2023 22:42:30 +0300 Subject: [PATCH 10/31] Methods_MedianStatistics --- ...AppleHealthKit+Methods_MedianStatistics.h} | 4 +- ...TAppleHealthKit+Methods_MedianStatistics.m | 179 ++++++++++++++++++ ...CAppleHealthKit_Methods_MedianStatistics.m | 50 ----- 3 files changed, 181 insertions(+), 52 deletions(-) rename RCTAppleHealthKit/{RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.h => RCTAppleHealthKit+Methods_MedianStatistics.h} (65%) create mode 100644 RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m delete mode 100644 RCTAppleHealthKit/RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.m diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.h b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.h similarity index 65% rename from RCTAppleHealthKit/RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.h rename to RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.h index 0716e198..66da5857 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.h +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.h @@ -1,5 +1,5 @@ // -// RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.h +// RCTAppleHealthKit+Methods_MedianStatistics.h // RCTAppleHealthKit // // Created by Anastasia Mishur on 14.03.23. @@ -8,7 +8,7 @@ #import "RCTAppleHealthKit.h" -@interface RCTAppleHealthKit (RTCAppleHealthKit_Methods_MedianStatistics) +@interface RCTAppleHealthKit (Methods_MedianStatistics) - (void)statistics_getMedianStatistic:(NSArray *)input callback:(RCTResponseSenderBlock)callback; diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m new file mode 100644 index 00000000..5faa3a37 --- /dev/null +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m @@ -0,0 +1,179 @@ +// +// RCTAppleHealthKit+Methods_MedianStatistics.m +// RCTAppleHealthKit +// +// Created by Anastasia Mishur on 14.03.23. +// Copyright © 2023 Greg Wilson. All rights reserved. +// + +#import "RCTAppleHealthKit+Methods_MedianStatistics.h" +#import "RCTAppleHealthKit+TypesForMedianStatistic.h" +#import "RCTAppleHealthKit+Queries.h" +#import "RCTAppleHealthKit+Utils.h" + +#import + +@implementation RCTAppleHealthKit (RTCAppleHealthKit_Methods_MedianStatistics) + +// MARK: - Public + +- (void)statistics_getMedianStatistic:(NSArray *)input callback:(RCTResponseSenderBlock)callback { + + NSDate *startDate = [NSDate dateWithTimeIntervalSince1970:0]; + NSDate *endDate = [NSDate date]; + + NSMutableArray *output = [NSMutableArray new]; + + // prepare object from input values + NSMutableDictionary *validSamples = [NSMutableDictionary new]; + for(NSString *sampleName in input) { + HKSampleType *sampleValue =(HKSampleType *)[self getObjectFromText:sampleName]; + if (sampleValue != nil) { + validSamples[sampleName] = sampleValue; + } + } + + NSOperationQueue *queue = [[NSOperationQueue alloc] init]; + queue.maxConcurrentOperationCount = 5; + + NSOperation *doneOperation = [[NSOperation alloc] init]; + [doneOperation setCompletionBlock:^{ + callback(@[[NSNull null], output]); + return; + }]; + + for(NSString *sampleName in [validSamples allKeys]) { + + NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ + + HKSampleType *sample = validSamples[sampleName]; + + int limit = 100; + __block HKQueryAnchor *anchor = nil; + __block NSMutableArray<__kindof HKSample *> *resultArray = [NSMutableArray new]; + __block NSMutableArray<__kindof HKSample *> *samplesFirstByDate = [NSMutableArray new]; + __block NSMutableArray<__kindof HKSample *> *samplesLastByDate = [NSMutableArray new]; + __block BOOL hasResults = YES; + __block NSString *anchorString = nil; + + while (hasResults) { + if (anchorString != nil) { + NSData* anchorData = [[NSData alloc] initWithBase64EncodedString:anchorString options:0]; + anchor = [NSKeyedUnarchiver unarchiveObjectWithData:anchorData]; + } + + NSPredicate *predicate = [RCTAppleHealthKit predicateForAnchoredQueries:anchor startDate:startDate endDate:endDate]; + + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + + [self fetchBatchOfSamples:sample + predicate:predicate + anchor:anchor + limit:limit + completion:^(NSDictionary *results, NSError *error) { + + if (results) { + @try { + + NSMutableArray<__kindof HKSample *> *data = results[@"data"]; + + if ([sample isKindOfClass:[HKWorkoutType class]]) { + NSMutableArray<__kindof HKSample *> *dataByActivityType = [NSMutableArray new]; + + for(HKWorkout *sampleElement in data) { + NSString *type = [RCTAppleHealthKit stringForHKWorkoutActivityType:[sampleElement workoutActivityType]]; + if ([type isEqualToString:sampleName]) { + [dataByActivityType addObject:sampleElement]; + } + } + + data = dataByActivityType; + } + + if (data.count > 0) { + [resultArray addObjectsFromArray:data]; + + //re-assign anchor + anchorString = results[@"anchor"]; + + // find very first and last, and save them + HKSample *firstFromFetched = [RCTAppleHealthKit firstByDateFromSamples:data]; + [samplesFirstByDate addObject:firstFromFetched]; + + HKSample *lastFromFetched = [RCTAppleHealthKit lastByDateFromSamples:data]; + [samplesLastByDate addObject:lastFromFetched]; + + } else { + hasResults = NO; + } + dispatch_semaphore_signal(semaphore); + } @catch (NSException *exception) { + hasResults = NO; + NSLog(@"RNHealth getMedianStatistic: An error occured"); + dispatch_semaphore_signal(semaphore); + } + } else { + hasResults = NO; + NSLog(@"RNHealthgetMedianStatistic: An error occured"); + dispatch_semaphore_signal(semaphore); + } + }]; + + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + }; + + if (resultArray.count != 0) { + + NSMutableArray *intervalsInSecond = [NSMutableArray new]; + NSMutableArray *intervalsInDays = [NSMutableArray new]; + int i = 0; + while (i < resultArray.count - 1) + { + HKSample *first = resultArray[i]; + HKSample *second = resultArray[i + 1]; + + NSDate *startInterval = second.startDate; + NSDate *endInterval = first.endDate; + + // count median for array of interval in seconds + NSTimeInterval secondsBetween = fabs([endInterval timeIntervalSinceDate:startInterval]); + NSNumber *seconds = [NSNumber numberWithDouble:secondsBetween]; + [intervalsInSecond addObject:seconds]; + + // count median for array of interval in days + NSNumber *days = [NSNumber numberWithInteger:[RCTAppleHealthKit daysFromSeconds:startInterval endDate:endInterval]]; + [intervalsInDays addObject:days]; + + i++; + }; + + NSNumber *medianIntervalInSeconds = [RCTAppleHealthKit calculateMedian:intervalsInSecond]; + NSNumber *medianIntervalInDays = [RCTAppleHealthKit calculateMedian:intervalsInDays]; + + HKSample *firstSample = [RCTAppleHealthKit firstByDateFromSamples:samplesFirstByDate]; + HKSample *lastSample = [RCTAppleHealthKit lastByDateFromSamples:samplesLastByDate]; + + NSString *resultStartDateString = [RCTAppleHealthKit buildISO8601StringFromDate:firstSample.startDate]; + NSString *resultEndDateString = [RCTAppleHealthKit buildISO8601StringFromDate:lastSample.endDate]; + + NSDictionary *response = @{ + @"parameterName" : sampleName, + @"firstEntry" : resultStartDateString, + @"lastEntry" : resultEndDateString, + @"entryCount" : @(resultArray.count), + @"medianSeconds" : medianIntervalInSeconds, + @"medianDays" : medianIntervalInDays, + }; + [output addObject:response]; + } + + }]; + [queue addOperation:operation]; + [doneOperation addDependency:operation]; + } + + [queue addOperation:doneOperation]; + +} + +@end diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.m b/RCTAppleHealthKit/RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.m deleted file mode 100644 index 54fde51c..00000000 --- a/RCTAppleHealthKit/RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.m +++ /dev/null @@ -1,50 +0,0 @@ -// -// RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.m -// RCTAppleHealthKit -// -// Created by Anastasia Mishur on 14.03.23. -// Copyright © 2023 Greg Wilson. All rights reserved. -// - -#import "RCTAppleHealthKit+RTCAppleHealthKit_Methods_MedianStatistics.h" -#import "RCTAppleHealthKit+Queries.h" -#import "RCTAppleHealthKit+Utils.h" -#import "RCTAppleHealthKit+TypesAndPermissions.h" -#import "RTCAppleHealthKit+Methods_Statistics.h" - -#import - -@implementation RCTAppleHealthKit (RTCAppleHealthKit_Methods_MedianStatistics) - -// MARK: - Public - -- (void)statistics_getMedianStatistic:(NSArray *)input callback:(RCTResponseSenderBlock)callback { - - NSLog(@"Have input: first element is - %@", input.firstObject); - - - //fake callback - NSMutableArray* output = [NSMutableArray new]; - NSDictionary *response1 = @{ - @"parameter" : @"weight", - @"firstEntry" : @"first date", - @"lastEntry" : @"last date", - @"entryCount" : @23, - @"medianDays" : @4, - }; - [output addObject:response1]; - - NSDictionary *response2 = @{ - @"parameter" : @"height", - @"firstEntry" : @"first date", - @"lastEntry" : @"last date", - @"entryCount" : @15, - @"medianDays" : @2, - }; - [output addObject:response2]; - - callback(@[[NSNull null], output]); - -} - -@end From 27144585d091f46f549889c54863f55edb2e6abc Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Wed, 22 Mar 2023 23:34:52 +0300 Subject: [PATCH 11/31] fix for Workout type --- RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m index 5faa3a37..e11c9f17 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m @@ -77,7 +77,7 @@ - (void)statistics_getMedianStatistic:(NSArray *)input callback:(RCTResponseSend NSMutableArray<__kindof HKSample *> *data = results[@"data"]; - if ([sample isKindOfClass:[HKWorkoutType class]]) { + if (([sample isKindOfClass:[HKWorkoutType class]]) && (![@"Workout" isEqual:sampleName])) { NSMutableArray<__kindof HKSample *> *dataByActivityType = [NSMutableArray new]; for(HKWorkout *sampleElement in data) { From 43dd95f82ffc71e96f8133ffcaf2e9b1fadbb286 Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Wed, 22 Mar 2023 23:59:12 +0300 Subject: [PATCH 12/31] constants for statistic added --- index.js | 2 ++ src/constants/MedianStatisticsDataTypes.js | 13 +++++++++++++ src/constants/index.js | 2 ++ 3 files changed, 17 insertions(+) create mode 100644 src/constants/MedianStatisticsDataTypes.js diff --git a/index.js b/index.js index d848b8e3..809e7053 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,7 @@ import { Activities, GenericStatisticsAggregators, + MedianStatisticsDataTypes, Observers, Permissions, StatisticsIntervals, @@ -14,6 +15,7 @@ export const HealthKit = Object.assign({}, AppleHealthKit, { Constants: { Activities, GenericStatisticsAggregators, + MedianStatisticsDataTypes, Observers, Permissions, StatisticsIntervals, diff --git a/src/constants/MedianStatisticsDataTypes.js b/src/constants/MedianStatisticsDataTypes.js new file mode 100644 index 00000000..2f7b3f19 --- /dev/null +++ b/src/constants/MedianStatisticsDataTypes.js @@ -0,0 +1,13 @@ +/** + * Apple Health Data Types For Median Statistic + * + * @type {Object} + */ + + import { Activities } from './Activities' + import { Permissions } from './Permissions' + + export const MedianStatisticsDataTypes = { + ...Activities, + ...Permissions + } diff --git a/src/constants/index.js b/src/constants/index.js index 4f88fb49..09a90b35 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -1,4 +1,5 @@ import { Activities } from './Activities' +import { MedianStatisticsDataTypes } from './MedianStatisticsDataTypes' import { Observers } from './Observers' import { Permissions } from './Permissions' import { GenericStatisticsAggregators, StepsStatisticsAggregators } from './StatisticsAggregators'; @@ -8,6 +9,7 @@ import { Units } from './Units' export { Activities, GenericStatisticsAggregators, + MedianStatisticsDataTypes, Observers, Permissions, StatisticsIntervals, From bf74016eb13205bb264bbfec5908ec2ac11f6666 Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Thu, 23 Mar 2023 01:03:00 +0300 Subject: [PATCH 13/31] input type changed to NSDictionary --- ...TAppleHealthKit+Methods_MedianStatistics.h | 2 +- ...TAppleHealthKit+Methods_MedianStatistics.m | 15 +++++++++++++-- RCTAppleHealthKit/RCTAppleHealthKit+Utils.h | 2 ++ RCTAppleHealthKit/RCTAppleHealthKit+Utils.m | 9 +++++++++ RCTAppleHealthKit/RCTAppleHealthKit.m | 2 +- index.d.ts | 19 +++++++++++++++++++ 6 files changed, 45 insertions(+), 4 deletions(-) diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.h b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.h index 66da5857..dc67ba93 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.h +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.h @@ -10,6 +10,6 @@ @interface RCTAppleHealthKit (Methods_MedianStatistics) -- (void)statistics_getMedianStatistic:(NSArray *)input callback:(RCTResponseSenderBlock)callback; +- (void)statistics_getMedianStatistic:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback; @end diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m index e11c9f17..9c573a9c 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m @@ -17,7 +17,12 @@ @implementation RCTAppleHealthKit (RTCAppleHealthKit_Methods_MedianStatistics) // MARK: - Public -- (void)statistics_getMedianStatistic:(NSArray *)input callback:(RCTResponseSenderBlock)callback { +- (void)statistics_getMedianStatistic:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback { + NSArray<__kindof NSString *> *types = [RCTAppleHealthKit typesFromOptions:input]; + if (types.count == 0) { + callback(@[RCTMakeError(@"No data types provided", nil, nil)]); + return; + } NSDate *startDate = [NSDate dateWithTimeIntervalSince1970:0]; NSDate *endDate = [NSDate date]; @@ -26,8 +31,14 @@ - (void)statistics_getMedianStatistic:(NSArray *)input callback:(RCTResponseSend // prepare object from input values NSMutableDictionary *validSamples = [NSMutableDictionary new]; - for(NSString *sampleName in input) { + for(NSString *sampleName in types) { HKSampleType *sampleValue =(HKSampleType *)[self getObjectFromText:sampleName]; + + if ([sampleValue isKindOfClass:[HKCharacteristicType class]]) { + NSLog(@"RNHealth: Could not load data for HKCharacteristicType: %@", sampleName); + continue; + } + if (sampleValue != nil) { validSamples[sampleName] = sampleValue; } diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Utils.h b/RCTAppleHealthKit/RCTAppleHealthKit+Utils.h index b49855f5..b4da105c 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Utils.h +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Utils.h @@ -10,6 +10,7 @@ #import "RCTTypes.h" extern NSString * const kMetadataKey; +extern NSString * const kTypesKey; @interface RCTAppleHealthKit (Utils) @@ -41,6 +42,7 @@ extern NSString * const kMetadataKey; + (HKWorkoutActivityType)hkWorkoutActivityTypeFromOptions: (NSDictionary *)options key: (NSString *)key withDefault: (HKWorkoutActivityType)defaultValue; + (HKQuantity *)hkQuantityFromOptions:(NSDictionary *)options valueKey: (NSString *)valueKey unitKey: (NSString *)unitKey; + (NSDictionary *)metadataFromOptions:(NSDictionary *)options withDefault:(NSDictionary *)defaultValue; ++ (NSArray *)typesFromOptions:(NSDictionary *)options; + (NSMutableArray *)reverseNSMutableArray:(NSMutableArray *)array; + (NSString *) stringForHKWorkoutActivityType:(int) enumValue; diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Utils.m b/RCTAppleHealthKit/RCTAppleHealthKit+Utils.m index 66ac3a5b..ecb4a9d7 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Utils.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Utils.m @@ -11,6 +11,7 @@ #import "RCTAppleHealthKit+TypesAndPermissions.h" NSString * const kMetadataKey = @"metadata"; +NSString * const kTypesKey = @"types"; @implementation RCTAppleHealthKit (Utils) @@ -414,6 +415,14 @@ + (NSDictionary *)metadataFromOptions:(NSDictionary *)options withDefault:(NSDic return metadata; } ++ (NSArray *)typesFromOptions:(NSDictionary *)options { + NSArray *types = [options objectForKey:kTypesKey]; + if(types == nil){ + return [NSArray new]; + } + return types; +} + + (NSMutableArray *)reverseNSMutableArray:(NSMutableArray *)array { if ([array count] <= 1) return array; diff --git a/RCTAppleHealthKit/RCTAppleHealthKit.m b/RCTAppleHealthKit/RCTAppleHealthKit.m index 5885758c..8aef8ff4 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit.m @@ -595,7 +595,7 @@ + (BOOL)requiresMainQueueSetup [self statistics_getStatisticRestingHeartRate:input callback:callback]; } -RCT_EXPORT_METHOD(getMedianStatistic:(NSArray *)input callback:(RCTResponseSenderBlock)callback) +RCT_EXPORT_METHOD(getMedianStatistic:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback) { [self _initializeHealthStore]; [self statistics_getMedianStatistic:input callback:callback]; diff --git a/index.d.ts b/index.d.ts index 3741d526..7c59c74e 100644 --- a/index.d.ts +++ b/index.d.ts @@ -469,6 +469,11 @@ declare module 'react-native-health' { callback: (err: string, results: Array) => void, ): void + getMedianStatistic( + options: HealthMedianStatisticsInputOptions, + callback: (err: string, results: Array) => void, + ): void + Constants: Constants } @@ -495,6 +500,15 @@ declare module 'react-native-health' { value: number } + export interface HealthStatisticsMedianValue { + parameterName: string, + firstEntry: string, + medianSeconds: number, + lastEntry: string, + medianDays: number, + entryCount: number + } + export interface SleepValue extends BaseValue { value: 'INBED' | 'ASLEEP' | 'CORE' | 'DEEP' | 'REM' | 'AWAKE' | 'UNKNOWN' sourceName: string @@ -566,6 +580,11 @@ declare module 'react-native-health' { startDate?: string endDate?: string } + + export interface HealthMedianStatisticsInputOptions { + types: (string[])[] + } + export interface HKWorkoutQueriedSampleType { activityId: number activityName: string From 88a431b69f160e35749e80fa8499ee7650312123 Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Thu, 23 Mar 2023 01:36:42 +0300 Subject: [PATCH 14/31] Create getMedianStatistic.md --- getMedianStatistic.md | 51 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 getMedianStatistic.md diff --git a/getMedianStatistic.md b/getMedianStatistic.md new file mode 100644 index 00000000..faebbd1f --- /dev/null +++ b/getMedianStatistic.md @@ -0,0 +1,51 @@ +# getMedianStatistic + +Query for median between entries. The options object is used to setup a query to retrieve relevant data. + +Example input options: + +```javascript +const options = { + types: [AppleHealthKit.Constants.MedianStatisticsDataTypes.Weight, + AppleHealthKit.Constants.MedianStatisticsDataTypes.HeartRate, + AppleHealthKit.Constants.MedianStatisticsDataTypes.Running, + AppleHealthKit.Constants.MedianStatisticsDataTypes.Workout] +}; +``` +```javascript +AppleHealthKit.getMedianStatistic( + input, + (callbackError: string, results: HealthValue[]) => { + console.log(results); + }, +); +``` + +Example output: +```json +[ + { + "parameterName": "Weight", + "firstEntry": "2023-03-13T21:28:00.000+0300", + "medianSeconds": 69660, + "lastEntry": "2023-03-17T17:32:00.000+0300", + "medianDays": 0, + "entryCount": 11 }, + { + "parameterName": "HeartRate", + "firstEntry": "2023-03-14T22:49:00.000+0300", + "medianSeconds": 86400, + "lastEntry": "2023-03-16T22:49:00.000+0300", + "medianDays": 1, + "entryCount": 3 + } +] +``` + +Permissions for input data types should be requested before calling the method, otherwise method will return no data for unresolved data types. +Median statistics available for any data type, which is possible to request permissions for (see Permissions), and also for Activity types (see Activities). It means, that could be requested both type 'Workout' for common workout data and 'Running' or any other Activity type. +Median statistic not available for HKCharacteristicType according to HealthKit documentation . + +Median counted for intervals between entries from 00:00:00 UTC on 1 January 1970 till current Date and returned in days and seconds. + + From 552abc7637bc44d83fb830de5a533eb2557ee9ab Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Thu, 23 Mar 2023 01:38:43 +0300 Subject: [PATCH 15/31] replace getMedianStatistic.md --- getMedianStatistic.md => docs/getMedianStatistic.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename getMedianStatistic.md => docs/getMedianStatistic.md (100%) diff --git a/getMedianStatistic.md b/docs/getMedianStatistic.md similarity index 100% rename from getMedianStatistic.md rename to docs/getMedianStatistic.md From b988e0e348f66823c722b48ca4dcc6b632dfc8db Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Thu, 23 Mar 2023 01:42:51 +0300 Subject: [PATCH 16/31] Update getMedianStatistic.md --- docs/getMedianStatistic.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/getMedianStatistic.md b/docs/getMedianStatistic.md index faebbd1f..d50755b9 100644 --- a/docs/getMedianStatistic.md +++ b/docs/getMedianStatistic.md @@ -42,9 +42,14 @@ Example output: ] ``` -Permissions for input data types should be requested before calling the method, otherwise method will return no data for unresolved data types. -Median statistics available for any data type, which is possible to request permissions for (see Permissions), and also for Activity types (see Activities). It means, that could be requested both type 'Workout' for common workout data and 'Running' or any other Activity type. -Median statistic not available for HKCharacteristicType according to HealthKit documentation . +Permissions for input data types should be requested before calling the method, otherwise method will return no data for unresolved data types. + + +Median statistics available for any data type, which is possible to request permissions for (see Permissions), and also for Activity types (see Activities). It means, that could be requested both type 'Workout' for common workout data and 'Running' or any other Activity type. + + +Median statistic not available for HKCharacteristicType according to HealthKit documentation. + Median counted for intervals between entries from 00:00:00 UTC on 1 January 1970 till current Date and returned in days and seconds. From f0a3fe5bc742ae9622a92ebc77d0ba267b48f0e1 Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Thu, 23 Mar 2023 19:16:18 +0300 Subject: [PATCH 17/31] Update package.json --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 07564578..ba104372 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "repository": { "type": "git", - "url": "git+ssh://git@github.com/mobileapps23/react-native-healthkit.git" + "url": "git+https://github.com/agencyenterprise/react-native-healthkit.git" }, "keywords": [ "Apple", @@ -18,7 +18,7 @@ "ios" ], "bugs": { - "url": "https://github.com/mobileapps23/react-native-healthkit/issues" + "url": "https://github.com/agencyenterprise/react-native-healthkit/issues" }, "license": "MIT", "devDependencies": { From 3823c3ab0b1e2dd62e4953567fad9677fa0c8913 Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Thu, 23 Mar 2023 19:22:07 +0300 Subject: [PATCH 18/31] Update README.md --- docs/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/README.md b/docs/README.md index 8e413257..ae3e1056 100644 --- a/docs/README.md +++ b/docs/README.md @@ -120,3 +120,7 @@ There is a gitbook version for the documentation on this [link](https://vinicius - [getAnchoredWorkouts](getAnchoredWorkouts.md) - [saveWorkout](saveWorkout.md) + +#### Statistics Methods + +- [getMedianStatistic](getMedianStatistic.md) From 19c3b75dbbb629c296d7a8e7fe6c276d3ccc8d29 Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Tue, 28 Mar 2023 12:42:47 +0300 Subject: [PATCH 19/31] remove copyrights --- RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.h | 1 - RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m | 1 - 2 files changed, 2 deletions(-) diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.h b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.h index dc67ba93..2e6f9f22 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.h +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.h @@ -3,7 +3,6 @@ // RCTAppleHealthKit // // Created by Anastasia Mishur on 14.03.23. -// Copyright © 2023 Greg Wilson. All rights reserved. // #import "RCTAppleHealthKit.h" diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m index 9c573a9c..69480720 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m @@ -3,7 +3,6 @@ // RCTAppleHealthKit // // Created by Anastasia Mishur on 14.03.23. -// Copyright © 2023 Greg Wilson. All rights reserved. // #import "RCTAppleHealthKit+Methods_MedianStatistics.h" From 622a7bafc2f298017321820f3ad53309dd2be663 Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Tue, 28 Mar 2023 12:51:46 +0300 Subject: [PATCH 20/31] documentation fixed --- README.md | 1 + docs/getMedianStatistic.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 208d652f..84d0dbe8 100644 --- a/README.md +++ b/README.md @@ -267,6 +267,7 @@ they are splitted in the following categories #### Statistics (Aggregated) Methods - [Statistics (Aggregated) methods](docs/statistics.md) +- [getMedianStatistic](getMedianStatistic.md) ## Additional Information diff --git a/docs/getMedianStatistic.md b/docs/getMedianStatistic.md index d50755b9..74b51959 100644 --- a/docs/getMedianStatistic.md +++ b/docs/getMedianStatistic.md @@ -45,7 +45,7 @@ Example output: Permissions for input data types should be requested before calling the method, otherwise method will return no data for unresolved data types. -Median statistics available for any data type, which is possible to request permissions for (see Permissions), and also for Activity types (see Activities). It means, that could be requested both type 'Workout' for common workout data and 'Running' or any other Activity type. +Median statistics available for any data type, which is possible to request permissions for (see [Permissions](permissions.md)), and also for Activity types (see [Activities](activities.md)). It means, that could be requested both type 'Workout' for common workout data and 'Running' or any other Activity type. Median statistic not available for HKCharacteristicType according to HealthKit documentation. From 1865a7b3045f52de8e72baf8c9930b17a965b18b Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Tue, 28 Mar 2023 14:48:59 +0300 Subject: [PATCH 21/31] Delete RCTAppleHealthKit.xcscheme --- .../xcschemes/RCTAppleHealthKit.xcscheme | 67 ------------------- 1 file changed, 67 deletions(-) delete mode 100644 RCTAppleHealthKit.xcodeproj/xcshareddata/xcschemes/RCTAppleHealthKit.xcscheme diff --git a/RCTAppleHealthKit.xcodeproj/xcshareddata/xcschemes/RCTAppleHealthKit.xcscheme b/RCTAppleHealthKit.xcodeproj/xcshareddata/xcschemes/RCTAppleHealthKit.xcscheme deleted file mode 100644 index 6ed10c11..00000000 --- a/RCTAppleHealthKit.xcodeproj/xcshareddata/xcschemes/RCTAppleHealthKit.xcscheme +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - From e4c0ada6d8d90d3952d72ebb04f2f31ca558a159 Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Thu, 30 Mar 2023 13:32:10 +0300 Subject: [PATCH 22/31] statictis method input data types updated --- ...TAppleHealthKit+Methods_MedianStatistics.m | 10 +- ...CTAppleHealthKit+TypesForMedianStatistic.m | 518 +++++++++++++++--- 2 files changed, 446 insertions(+), 82 deletions(-) diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m index 69480720..aa184089 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m @@ -19,7 +19,7 @@ @implementation RCTAppleHealthKit (RTCAppleHealthKit_Methods_MedianStatistics) - (void)statistics_getMedianStatistic:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback { NSArray<__kindof NSString *> *types = [RCTAppleHealthKit typesFromOptions:input]; if (types.count == 0) { - callback(@[RCTMakeError(@"No data types provided", nil, nil)]); + callback(@[RCTMakeError(@"RNHealth: No data types provided", nil, nil)]); return; } @@ -40,6 +40,9 @@ - (void)statistics_getMedianStatistic:(NSDictionary *)input callback:(RCTRespons if (sampleValue != nil) { validSamples[sampleName] = sampleValue; + } else { + NSLog(@"RNHealth: Could not load data for type: %@", sampleName); + continue; } } @@ -87,12 +90,13 @@ - (void)statistics_getMedianStatistic:(NSDictionary *)input callback:(RCTRespons NSMutableArray<__kindof HKSample *> *data = results[@"data"]; - if (([sample isKindOfClass:[HKWorkoutType class]]) && (![@"Workout" isEqual:sampleName])) { + if (([sample isKindOfClass:[HKWorkoutType class]]) && (![@"workout" isEqual:sampleName])) { NSMutableArray<__kindof HKSample *> *dataByActivityType = [NSMutableArray new]; for(HKWorkout *sampleElement in data) { NSString *type = [RCTAppleHealthKit stringForHKWorkoutActivityType:[sampleElement workoutActivityType]]; - if ([type isEqualToString:sampleName]) { + + if ([type caseInsensitiveCompare:sampleName] == NSOrderedSame) { [dataByActivityType addObject:sampleElement]; } } diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+TypesForMedianStatistic.m b/RCTAppleHealthKit/RCTAppleHealthKit+TypesForMedianStatistic.m index b933bbd6..5df30d0f 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+TypesForMedianStatistic.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit+TypesForMedianStatistic.m @@ -11,7 +11,7 @@ @implementation RCTAppleHealthKit (TypesForMedianStatistic) - (nullable HKSampleType *)getObjectFromText:(nonnull NSString*)key { - HKSampleType * _Nullable sample = (HKSampleType *)[self getReadPermFromText:key]; + HKSampleType * _Nullable sample = (HKSampleType *)[self getObjectForDataType:key]; if (sample != nil) { return sample; } else { @@ -20,6 +20,365 @@ - (nullable HKSampleType *)getObjectFromText:(nonnull NSString*)key { } } +- (nullable HKObjectType *)getObjectForDataType:(nonnull NSString*)key { + UIDevice *deviceInfo = [UIDevice currentDevice]; + float systemVersion = deviceInfo.systemVersion.floatValue; + + // documented lower iOS version + if (systemVersion < 8.0) { + return nil; + } + + // HKQuantityType Identifiers + + if ([@"stepCount" isEqualToString: key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]; + } else if ([@"distanceWalkingRunning" isEqualToString: key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning]; + } else if ([@"runningGroundContactTime" isEqualToString: key] && systemVersion >= 16.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierRunningGroundContactTime]; + } else if ([@"runningPower" isEqualToString: key] && systemVersion >= 16.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierRunningPower]; + } else if ([@"runningSpeed" isEqualToString: key] && systemVersion >= 16.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierRunningSpeed]; + } else if ([@"runningStrideLength" isEqualToString: key] && systemVersion >= 16.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierRunningStrideLength]; + } else if ([@"runningVerticalOscillation" isEqualToString: key] && systemVersion >= 16.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierRunningVerticalOscillation]; + } else if ([@"distanceCycling" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceCycling]; + } else if ([@"pushCount" isEqualToString: key] && systemVersion >= 10.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierPushCount]; + } else if ([@"distanceWheelchair" isEqualToString: key] && systemVersion >= 10.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWheelchair]; + } else if ([@"swimmingStrokeCount" isEqualToString: key] && systemVersion >= 10.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierSwimmingStrokeCount]; + } else if ([@"distanceSwimming" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceSwimming]; + } else if ([@"distanceDownhillSnowSports" isEqualToString: key] && systemVersion >= 11.2) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceDownhillSnowSports]; + } else if ([@"basalEnergyBurned" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBasalEnergyBurned]; + } else if ([@"activeEnergyBurned" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierActiveEnergyBurned]; + } else if ([@"flightsClimbed" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierFlightsClimbed]; + } else if ([@"nikeFuel" isEqualToString: key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierNikeFuel]; + } else if ([@"appleExerciseTime" isEqualToString: key] && systemVersion >= 9.3) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierAppleExerciseTime]; + } else if ([@"appleMoveTime" isEqualToString: key] && systemVersion >= 14.5) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierAppleMoveTime]; + } else if ([@"appleStandTime" isEqualToString: key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierAppleStandTime]; + } else if ([@"vo2Max" isEqualToString: key] && systemVersion >= 11.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierVO2Max]; + } else if ([@"height" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeight]; + } else if ([@"bodyMass" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass]; + } else if ([@"bodyMassIndex" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMassIndex]; + } else if ([@"leanBodyMass" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierLeanBodyMass]; + } else if ([@"bodyFatPercentage" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyFatPercentage]; + } else if ([@"waistCircumference" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierWaistCircumference]; + } else if ([@"appleSleepingWristTemperature" isEqualToString: key] && systemVersion >= 16.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierAppleSleepingWristTemperature]; + } else if ([@"basalBodyTemperature" isEqualToString: key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBasalBodyTemperature]; + } else if ([@"environmentalAudioExposure" isEqualToString: key] && systemVersion >= 13.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierEnvironmentalAudioExposure]; + } else if ([@"headphoneAudioExposure" isEqualToString: key] && systemVersion >= 13.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeadphoneAudioExposure]; + } else if ([@"heartRate" isEqualToString: key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate]; + } else if ([@"restingHeartRate" isEqualToString: key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierRestingHeartRate]; + } else if ([@"walkingHeartRateAverage" isEqualToString: key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierWalkingHeartRateAverage]; + } else if ([@"heartRateVariabilitySDNN" isEqualToString: key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRateVariabilitySDNN]; + } else if ([@"heartRateRecoveryOneMinute" isEqualToString: key] && systemVersion >= 16.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRateRecoveryOneMinute]; + } else if ([@"atrialFibrillationBurden" isEqualToString: key] && systemVersion >= 16.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierAtrialFibrillationBurden]; + } else if ([@"oxygenSaturation" isEqualToString: key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierOxygenSaturation]; + } else if ([@"bodyTemperature" isEqualToString: key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyTemperature]; + } else if ([@"bloodPressureSystolic" isEqualToString: key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodPressureSystolic]; + } else if ([@"bloodPressureDiastolic" isEqualToString: key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodPressureDiastolic]; + } else if ([@"respiratoryRate" isEqualToString: key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierRespiratoryRate]; + } else if ([@"bloodGlucose" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodGlucose]; + } else if ([@"electrodermalActivity" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierElectrodermalActivity]; + } else if ([@"forcedExpiratoryVolume1" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierForcedExpiratoryVolume1]; + } else if ([@"forcedVitalCapacity" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierForcedVitalCapacity]; + } else if ([@"inhalerUsage" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierInhalerUsage]; + } else if ([@"insulinDelivery" isEqualToString:key] && systemVersion >= 11.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierInsulinDelivery]; + } else if ([@"numberOfTimesFallen" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierNumberOfTimesFallen]; + } else if ([@"peakExpiratoryFlowRate" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierPeakExpiratoryFlowRate]; + } else if ([@"peripheralPerfusionIndex" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierPeripheralPerfusionIndex]; + } else if ([@"dietaryBiotin" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryBiotin]; + } else if ([@"dietaryCaffeine" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryCaffeine]; + } else if ([@"dietaryCalcium" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryCalcium]; + } else if ([@"dietaryCarbohydrates" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryCarbohydrates]; + } else if ([@"dietaryChloride" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryChloride]; + } else if ([@"dietaryCholesterol" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryCholesterol]; + } else if ([@"dietaryChromium" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryChromium]; + } else if ([@"dietaryCopper" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryCopper]; + } else if ([@"dietaryEnergyConsumed" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryEnergyConsumed]; + } else if ([@"dietaryFatMonounsaturated" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryFatMonounsaturated]; + } else if ([@"dietaryFatPolyunsaturated" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryFatPolyunsaturated]; + } else if ([@"dietaryFatSaturated" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryFatSaturated]; + } else if ([@"dietaryFatTotal" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryFatTotal]; + } else if ([@"dietaryFiber" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryFiber]; + } else if ([@"dietaryFolate" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryFolate]; + } else if ([@"dietaryIodine" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryIodine]; + } else if ([@"dietaryIron" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryIron]; + } else if ([@"dietaryMagnesium" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryMagnesium]; + } else if ([@"dietaryManganese" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryManganese]; + } else if ([@"dietaryMolybdenum" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryMolybdenum]; + } else if ([@"dietaryNiacin" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryNiacin]; + } else if ([@"dietaryPantothenicAcid" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryPantothenicAcid]; + } else if ([@"dietaryPhosphorus" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryPhosphorus]; + } else if ([@"dietaryPotassium" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryPotassium]; + } else if ([@"dietaryProtein" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryProtein]; + } else if ([@"dietaryRiboflavin" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryRiboflavin]; + } else if ([@"dietarySelenium" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietarySelenium]; + } else if ([@"dietarySodium" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietarySodium]; + } else if ([@"dietarySugar" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietarySugar]; + } else if ([@"dietaryThiamin" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryThiamin]; + } else if ([@"dietaryVitaminA" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryVitaminA]; + } else if ([@"dietaryVitaminB12" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryVitaminB12]; + } else if ([@"dietaryVitaminB6" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryVitaminB6]; + } else if ([@"dietaryVitaminC" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryVitaminC]; + } else if ([@"dietaryVitaminD" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryVitaminD]; + } else if ([@"dietaryVitaminE" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryVitaminE]; + } else if ([@"dietaryVitaminK" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryVitaminK]; + } else if ([@"dietaryZinc" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryZinc]; + } else if ([@"dietaryWater" isEqualToString:key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDietaryWater]; + } else if ([@"bloodAlcoholContent" isEqualToString: key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodAlcoholContent]; + } else if ([@"numberOfAlcoholicBeverages" isEqualToString: key] && systemVersion >= 15.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierNumberOfAlcoholicBeverages]; + } else if ([@"appleWalkingSteadiness" isEqualToString: key] && systemVersion >= 15.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierAppleWalkingSteadiness]; + } else if ([@"sixMinuteWalkTestDistance" isEqualToString: key] && systemVersion >= 14.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierSixMinuteWalkTestDistance]; + } else if ([@"walkingSpeed" isEqualToString: key] && systemVersion >= 14.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierWalkingSpeed]; + } else if ([@"walkingStepLength" isEqualToString: key] && systemVersion >= 14.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierWalkingStepLength]; + } else if ([@"walkingAsymmetryPercentage" isEqualToString: key] && systemVersion >= 14.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierWalkingAsymmetryPercentage]; + } else if ([@"walkingDoubleSupportPercentage" isEqualToString: key] && systemVersion >= 14.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierWalkingDoubleSupportPercentage]; + } else if ([@"stairAscentSpeed" isEqualToString: key] && systemVersion >= 14.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStairAscentSpeed]; + } else if ([@"stairDescentSpeed" isEqualToString: key] && systemVersion >= 14.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStairDescentSpeed]; + } else if ([@"uvExposure" isEqualToString: key]) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierUVExposure]; + } else if ([@"underwaterDepth" isEqualToString: key] && systemVersion >= 16.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierUnderwaterDepth]; + } else if ([@"waterTemperature" isEqualToString: key] && systemVersion >= 16.0) { + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierWaterTemperature]; + } + + // HKCategoryType Identifiers + + if ([@"appleStandHour" isEqualToString: key]) { + return [HKObjectType quantityTypeForIdentifier:HKCategoryTypeIdentifierAppleStandHour]; + } else if ([@"lowCardioFitnessEvent" isEqualToString: key] && systemVersion >= 14.3) { + return [HKObjectType quantityTypeForIdentifier:HKCategoryTypeIdentifierLowCardioFitnessEvent]; + } else if ([@"menstrualFlow" isEqualToString: key]) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierMenstrualFlow]; + } else if ([@"intermenstrualBleeding" isEqualToString: key]) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierIntermenstrualBleeding]; + } else if ([@"infrequentMenstrualCycles" isEqualToString: key] && systemVersion >= 16.0) { + return [HKObjectType quantityTypeForIdentifier:HKCategoryTypeIdentifierInfrequentMenstrualCycles]; + } else if ([@"irregularMenstrualCycles" isEqualToString: key] && systemVersion >= 16.0) { + return [HKObjectType quantityTypeForIdentifier:HKCategoryTypeIdentifierIrregularMenstrualCycles]; + } else if ([@"persistentIntermenstrualBleeding" isEqualToString: key] && systemVersion >= 16.0) { + return [HKObjectType quantityTypeForIdentifier:HKCategoryTypeIdentifierPersistentIntermenstrualBleeding]; + } else if ([@"prolongedMenstrualPeriods" isEqualToString: key] && systemVersion >= 16.0) { + return [HKObjectType quantityTypeForIdentifier:HKCategoryTypeIdentifierProlongedMenstrualPeriods]; + } else if ([@"cervicalMucusQuality" isEqualToString: key] && systemVersion >= 9.0) { + return [HKObjectType quantityTypeForIdentifier:HKCategoryTypeIdentifierCervicalMucusQuality]; + } else if ([@"ovulationTestResult" isEqualToString: key]) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierOvulationTestResult]; + } else if ([@"progesteroneTestResult" isEqualToString: key] && systemVersion >= 15.0) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierProgesteroneTestResult]; + } else if ([@"sexualActivity" isEqualToString: key]) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierSexualActivity]; + } else if ([@"contraceptive" isEqualToString: key] && systemVersion >= 14.3) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierContraceptive]; + } else if ([@"pregnancy" isEqualToString: key] && systemVersion >= 14.3) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierPregnancy]; + } else if ([@"pregnancyTestResult" isEqualToString: key] && systemVersion >= 15.0) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierPregnancyTestResult]; + } else if ([@"lactation" isEqualToString: key] && systemVersion >= 14.3) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierLactation]; + } else if ([@"environmentalAudioExposureEvent" isEqualToString: key] && systemVersion >= 14.0) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierEnvironmentalAudioExposureEvent]; + } else if ([@"headphoneAudioExposureEvent" isEqualToString: key] && systemVersion >= 14.2) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierHeadphoneAudioExposureEvent]; + } else if ([@"lowHeartRateEvent" isEqualToString: key] && systemVersion >= 12.2) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierLowHeartRateEvent]; + } else if ([@"highHeartRateEvent" isEqualToString: key] && systemVersion >= 12.2) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierHighHeartRateEvent]; + } else if ([@"irregularHeartRhythmEvent" isEqualToString: key] && systemVersion >= 12.2) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierIrregularHeartRhythmEvent]; + } else if ([@"appleWalkingSteadinessEvent" isEqualToString: key] && systemVersion >= 15.0) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierAppleWalkingSteadinessEvent]; + } else if ([@"mindfulSession" isEqualToString: key] && systemVersion >= 10.0) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierMindfulSession]; + } else if ([@"sleepAnalysis" isEqualToString:key]) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierSleepAnalysis]; + } else if ([@"toothbrushingEvent" isEqualToString: key] && systemVersion >= 13.0) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierToothbrushingEvent]; + } else if ([@"handwashingEvent" isEqualToString: key] && systemVersion >= 14.0) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierHandwashingEvent]; + } + + // Symptoms + if ([@"abdominalCramps" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierAbdominalCramps]; + } else if ([@"bloating" isEqualToString: key] && systemVersion >= 13.6){ + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierBloating]; + } else if ([@"constipation" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierConstipation]; + } else if ([@"diarrhea" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierDiarrhea]; + } else if ([@"heartburn" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierHeartburn]; + } else if ([@"nausea" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierNausea]; + } else if ([@"vomiting" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierVomiting]; + } else if ([@"appetiteChanges" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierAppetiteChanges]; + } else if ([@"chills" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierChills]; + } else if ([@"dizziness" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierDizziness]; + } else if ([@"fainting" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierFainting]; + } else if ([@"fatigue" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierFatigue]; + } else if ([@"fever" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierFever]; + } else if ([@"generalizedBodyAche" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierGeneralizedBodyAche]; + } else if ([@"hotFlashes" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierHotFlashes]; + } else if ([@"chestTightnessOrPain" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierChestTightnessOrPain]; + } else if ([@"coughing" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierCoughing]; + } else if ([@"rapidPoundingOrFlutteringHeartbeat" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat]; + } else if ([@"shortnessOfBreath" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierShortnessOfBreath]; + } else if ([@"skippedHeartbeat" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierSkippedHeartbeat]; + } else if ([@"wheezing" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierWheezing]; + } else if ([@"lowerBackPain" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierLowerBackPain]; + } else if ([@"headache" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierHeadache]; + } else if ([@"memoryLapse" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierMemoryLapse]; + } else if ([@"moodChanges" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierMoodChanges]; + } else if ([@"lossOfSmell" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierLossOfSmell]; + } else if ([@"lossOfTaste" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierLossOfTaste]; + } else if ([@"runnyNose" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierRunnyNose]; + } else if ([@"soreThroat" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierSoreThroat]; + } else if ([@"sinusCongestion" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierSinusCongestion]; + } else if ([@"breastPain" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierBreastPain]; + } else if ([@"pelvicPain" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierPelvicPain]; + } else if ([@"vaginalDryness" isEqualToString: key] && systemVersion >= 14.0) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierVaginalDryness]; + } else if ([@"acne" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierAcne]; + } else if ([@"drySkin" isEqualToString: key] && systemVersion >= 14.0) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierDrySkin]; + } else if ([@"hairLoss" isEqualToString: key] && systemVersion >= 14.0) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierHairLoss]; + } else if ([@"nightSweats" isEqualToString: key] && systemVersion >= 14.0) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierNightSweats]; + } else if ([@"sleepChanges" isEqualToString: key] && systemVersion >= 13.6) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierSleepChanges]; + } else if ([@"bladderIncontinence" isEqualToString: key] && systemVersion >= 14.0) { + return [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierBladderIncontinence]; + } + + return nil; +} + - (nullable HKObjectType *)getObjectForActivityType:(nonnull NSString*)key { UIDevice *deviceInfo = [UIDevice currentDevice]; float systemVersion = deviceInfo.systemVersion.floatValue; @@ -29,118 +388,119 @@ - (nullable HKObjectType *)getObjectForActivityType:(nonnull NSString*)key { return nil; } - if ([@"AmericanFootball" isEqualToString: key] || - [@"Archery" isEqualToString: key] || - [@"AustralianFootball" isEqualToString: key] || - [@"Badminton" isEqualToString: key] || - [@"Baseball" isEqualToString: key] || - [@"Basketball" isEqualToString: key] || - [@"Bowling" isEqualToString: key] || - [@"Boxing" isEqualToString: key] || - [@"Climbing" isEqualToString: key] || - [@"Cricket" isEqualToString: key] || - [@"CrossTraining" isEqualToString: key] || - [@"Curling" isEqualToString: key] || - [@"Cycling" isEqualToString: key] || - [@"Elliptical" isEqualToString: key] || - [@"EquestrianSports" isEqualToString: key] || - [@"Fencing" isEqualToString: key] || - [@"Fishing" isEqualToString: key] || - [@"FunctionalStrengthTraining" isEqualToString: key] || - [@"Golf" isEqualToString: key] || - [@"Gymnastics" isEqualToString: key] || - [@"Handball" isEqualToString: key] || - [@"Hiking" isEqualToString: key] || - [@"Hockey" isEqualToString: key] || - [@"Hunting" isEqualToString: key] || - [@"Lacrosse" isEqualToString: key] || - [@"MartialArts" isEqualToString: key] || - [@"MindAndBody" isEqualToString: key] || - [@"PaddleSports" isEqualToString: key] || - [@"Play" isEqualToString: key] || - [@"PreparationAndRecovery" isEqualToString: key] || - [@"Racquetball" isEqualToString: key] || - [@"Rowing" isEqualToString: key] || - [@"Rugby" isEqualToString: key] || - [@"Running" isEqualToString: key] || - [@"Sailing" isEqualToString: key] || - [@"SkatingSports" isEqualToString: key] || - [@"SnowSports" isEqualToString: key] || - [@"Soccer" isEqualToString: key] || - [@"Softball" isEqualToString: key] || - [@"Squash" isEqualToString: key] || - [@"StairClimbing" isEqualToString: key] || - [@"SurfingSports" isEqualToString: key] || - [@"Swimming" isEqualToString: key] || - [@"TableTennis" isEqualToString: key] || - [@"Tennis" isEqualToString: key] || - [@"TrackAndField" isEqualToString: key] || - [@"TraditionalStrengthTraining" isEqualToString: key] || - [@"Volleyball" isEqualToString: key] || - [@"Walking" isEqualToString: key] || - [@"WaterFitness" isEqualToString: key] || - [@"WaterPolo" isEqualToString: key] || - [@"WaterSports" isEqualToString: key] || - [@"Wrestling" isEqualToString: key] || - [@"Yoga" isEqualToString: key]) { + if ([@"americanFootball" isEqualToString: key] || + [@"archery" isEqualToString: key] || + [@"australianFootball" isEqualToString: key] || + [@"badminton" isEqualToString: key] || + [@"baseball" isEqualToString: key] || + [@"basketball" isEqualToString: key] || + [@"bowling" isEqualToString: key] || + [@"boxing" isEqualToString: key] || + [@"climbing" isEqualToString: key] || + [@"cricket" isEqualToString: key] || + [@"crossTraining" isEqualToString: key] || + [@"curling" isEqualToString: key] || + [@"cycling" isEqualToString: key] || + [@"elliptical" isEqualToString: key] || + [@"equestrianSports" isEqualToString: key] || + [@"fencing" isEqualToString: key] || + [@"fishing" isEqualToString: key] || + [@"functionalStrengthTraining" isEqualToString: key] || + [@"golf" isEqualToString: key] || + [@"gymnastics" isEqualToString: key] || + [@"handball" isEqualToString: key] || + [@"hiking" isEqualToString: key] || + [@"hockey" isEqualToString: key] || + [@"hunting" isEqualToString: key] || + [@"lacrosse" isEqualToString: key] || + [@"martialArts" isEqualToString: key] || + [@"mindAndBody" isEqualToString: key] || + [@"paddleSports" isEqualToString: key] || + [@"play" isEqualToString: key] || + [@"preparationAndRecovery" isEqualToString: key] || + [@"racquetball" isEqualToString: key] || + [@"rowing" isEqualToString: key] || + [@"rugby" isEqualToString: key] || + [@"running" isEqualToString: key] || + [@"sailing" isEqualToString: key] || + [@"skatingSports" isEqualToString: key] || + [@"snowSports" isEqualToString: key] || + [@"soccer" isEqualToString: key] || + [@"softball" isEqualToString: key] || + [@"squash" isEqualToString: key] || + [@"stairClimbing" isEqualToString: key] || + [@"surfingSports" isEqualToString: key] || + [@"swimming" isEqualToString: key] || + [@"tableTennis" isEqualToString: key] || + [@"tennis" isEqualToString: key] || + [@"trackAndField" isEqualToString: key] || + [@"traditionalStrengthTraining" isEqualToString: key] || + [@"volleyball" isEqualToString: key] || + [@"walking" isEqualToString: key] || + [@"waterFitness" isEqualToString: key] || + [@"waterPolo" isEqualToString: key] || + [@"waterSports" isEqualToString: key] || + [@"workout" isEqualToString: key] || + [@"wrestling" isEqualToString: key] || + [@"yoga" isEqualToString: key]) { return [HKObjectType workoutType]; } - if ([@"Barre" isEqualToString: key] && systemVersion >= 10.0) { + if ([@"barre" isEqualToString: key] && systemVersion >= 10.0) { return [HKObjectType workoutType]; - } else if ([@"CoreTraining" isEqualToString: key] && systemVersion >= 10.0) { + } else if ([@"coreTraining" isEqualToString: key] && systemVersion >= 10.0) { return [HKObjectType workoutType]; - } else if ([@"CrossCountrySkiing" isEqualToString: key] && systemVersion >= 10.0) { + } else if ([@"crossCountrySkiing" isEqualToString: key] && systemVersion >= 10.0) { return [HKObjectType workoutType]; - } else if ([@"DownhillSkiing" isEqualToString: key] && systemVersion >= 10.0) { + } else if ([@"downhillSkiing" isEqualToString: key] && systemVersion >= 10.0) { return [HKObjectType workoutType]; - } else if ([@"Flexibility" isEqualToString: key] && systemVersion >= 10.0) { + } else if ([@"flexibility" isEqualToString: key] && systemVersion >= 10.0) { return [HKObjectType workoutType]; - } else if ([@"HighIntensityIntervalTraining" isEqualToString: key] && systemVersion >= 10.0) { + } else if ([@"highIntensityIntervalTraining" isEqualToString: key] && systemVersion >= 10.0) { return [HKObjectType workoutType]; - } else if ([@"JumpRope" isEqualToString: key] && systemVersion >= 10.0) { + } else if ([@"jumpRope" isEqualToString: key] && systemVersion >= 10.0) { return [HKObjectType workoutType]; - } else if ([@"Kickboxing" isEqualToString: key] && systemVersion >= 10.0) { + } else if ([@"kickboxing" isEqualToString: key] && systemVersion >= 10.0) { return [HKObjectType workoutType]; - } else if ([@"Pilates" isEqualToString: key] && systemVersion >= 10.0) { + } else if ([@"pilates" isEqualToString: key] && systemVersion >= 10.0) { return [HKObjectType workoutType]; - } else if ([@"Snowboarding" isEqualToString: key] && systemVersion >= 10.0) { + } else if ([@"snowboarding" isEqualToString: key] && systemVersion >= 10.0) { return [HKObjectType workoutType]; - } else if ([@"Stairs" isEqualToString: key] && systemVersion >= 10.0) { + } else if ([@"stairs" isEqualToString: key] && systemVersion >= 10.0) { return [HKObjectType workoutType]; - } else if ([@"StepTraining" isEqualToString: key] && systemVersion >= 10.0) { + } else if ([@"stepTraining" isEqualToString: key] && systemVersion >= 10.0) { return [HKObjectType workoutType]; - } else if ([@"WheelchairWalkPace" isEqualToString: key] && systemVersion >= 10.0) { + } else if ([@"wheelchairWalkPace" isEqualToString: key] && systemVersion >= 10.0) { return [HKObjectType workoutType]; - } else if ([@"WheelchairRunPace" isEqualToString: key] && systemVersion >= 10.0) { + } else if ([@"wheelchairRunPace" isEqualToString: key] && systemVersion >= 10.0) { return [HKObjectType workoutType]; } - if ([@"TaiChi" isEqualToString: key] && systemVersion >= 11.0) { + if ([@"taiChi" isEqualToString: key] && systemVersion >= 11.0) { return [HKObjectType workoutType]; - } else if ([@"MixedCardio" isEqualToString: key] && systemVersion >= 11.0) { + } else if ([@"mixedCardio" isEqualToString: key] && systemVersion >= 11.0) { return [HKObjectType workoutType]; - } else if ([@"HandCycling" isEqualToString: key] && systemVersion >= 11.0) { + } else if ([@"handCycling" isEqualToString: key] && systemVersion >= 11.0) { return [HKObjectType workoutType]; } - if ([@"DiscSports" isEqualToString: key] && systemVersion >= 13.0) { + if ([@"discSports" isEqualToString: key] && systemVersion >= 13.0) { return [HKObjectType workoutType]; - } else if ([@"FitnessGaming" isEqualToString: key] && systemVersion >= 13.0) { + } else if ([@"fitnessGaming" isEqualToString: key] && systemVersion >= 13.0) { return [HKObjectType workoutType]; } - if ([@"CardioDance" isEqualToString: key] && systemVersion >= 14.0) { + if ([@"cardioDance" isEqualToString: key] && systemVersion >= 14.0) { return [HKObjectType workoutType]; - } else if ([@"Cooldown" isEqualToString: key] && systemVersion >= 14.0) { + } else if ([@"cooldown" isEqualToString: key] && systemVersion >= 14.0) { return [HKObjectType workoutType]; - } else if ([@"Pickleball" isEqualToString: key] && systemVersion >= 14.0) { + } else if ([@"pickleball" isEqualToString: key] && systemVersion >= 14.0) { return [HKObjectType workoutType]; - } else if ([@"SocialDance" isEqualToString: key] && systemVersion >= 14.0) { + } else if ([@"socialDance" isEqualToString: key] && systemVersion >= 14.0) { return [HKObjectType workoutType]; } - if ([@"HKWorkoutActivityTypeSwimBikeRun" isEqualToString: key] && systemVersion >= 16.0) { + if ([@"swimBikeRun" isEqualToString: key] && systemVersion >= 16.0) { return [HKObjectType workoutType]; } From 08185793b54630535cf47ecf5ba45323ecbc64a1 Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Thu, 30 Mar 2023 14:52:48 +0300 Subject: [PATCH 23/31] method documentation updated --- docs/getMedianStatistic.md | 1066 +++++++++++++++++++++++++++++++++++- 1 file changed, 1058 insertions(+), 8 deletions(-) diff --git a/docs/getMedianStatistic.md b/docs/getMedianStatistic.md index 74b51959..5814fa8e 100644 --- a/docs/getMedianStatistic.md +++ b/docs/getMedianStatistic.md @@ -6,10 +6,7 @@ Example input options: ```javascript const options = { - types: [AppleHealthKit.Constants.MedianStatisticsDataTypes.Weight, - AppleHealthKit.Constants.MedianStatisticsDataTypes.HeartRate, - AppleHealthKit.Constants.MedianStatisticsDataTypes.Running, - AppleHealthKit.Constants.MedianStatisticsDataTypes.Workout] + types: ['heartRate', 'stepCount'] }; ``` ```javascript @@ -25,14 +22,14 @@ Example output: ```json [ { - "parameterName": "Weight", + "parameterName": "stepCount", "firstEntry": "2023-03-13T21:28:00.000+0300", "medianSeconds": 69660, "lastEntry": "2023-03-17T17:32:00.000+0300", "medianDays": 0, "entryCount": 11 }, { - "parameterName": "HeartRate", + "parameterName": "heartRate", "firstEntry": "2023-03-14T22:49:00.000+0300", "medianSeconds": 86400, "lastEntry": "2023-03-16T22:49:00.000+0300", @@ -45,7 +42,9 @@ Example output: Permissions for input data types should be requested before calling the method, otherwise method will return no data for unresolved data types. -Median statistics available for any data type, which is possible to request permissions for (see [Permissions](permissions.md)), and also for Activity types (see [Activities](activities.md)). It means, that could be requested both type 'Workout' for common workout data and 'Running' or any other Activity type. +Median statistics available for any data type, listed below, incl. Activity types (see [Activities](activities.md)). It means, that could be requested both type 'workout' for common workout data and 'running' or any other Activity type. + +Types name are case sensitive. Median statistic not available for HKCharacteristicType according to HealthKit documentation. @@ -53,4 +52,1055 @@ Median statistic not available for HKCharacteristicType according to HealthKit d Median counted for intervals between entries from 00:00:00 UTC on 1 January 1970 till current Date and returned in days and seconds. - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Quantity + Category + Symptom + Activity +
stepCount + appleStandHour + abdominalCramps + americanFootball +
distanceWalkingRunning + lowCardioFitnessEvent + bloating + archery +
runningGroundContactTime + menstrualFlow + constipation + australianFootball +
runningPower + intermenstrualBleeding + diarrhea + badminton +
runningSpeed + infrequentMenstrualCycles + heartburn + baseball +
runningStrideLength + irregularMenstrualCycles + nausea + basketball +
runningVerticalOscillation + persistentIntermenstrualBleeding + vomiting + bowling +
distanceCycling + prolongedMenstrualPeriods + appetiteChanges + boxing +
pushCount + cervicalMucusQuality + chills + climbing +
distanceWheelchair + ovulationTestResult + dizziness + cricket +
swimmingStrokeCount + progesteroneTestResult + fainting + crossTraining +
distanceSwimming + sexualActivity + fatigue + curling +
distanceDownhillSnowSports + contraceptive + fever + cycling +
basalEnergyBurned + pregnancy + generalizedBodyAche + elliptical +
activeEnergyBurned + pregnancyTestResult + hotFlashes + equestrianSports +
flightsClimbed + lactation + chestTightnessOrPain + fencing +
nikeFuel + environmentalAudioExposureEvent + coughing + fishing +
appleExerciseTime + headphoneAudioExposureEvent + rapidPoundingOrFlutteringHeartbeat + functionalStrengthTraining +
appleMoveTime + lowHeartRateEvent + shortnessOfBreath + golf +
appleStandTime + highHeartRateEvent + skippedHeartbeat + gymnastics +
vo2Max + irregularHeartRhythmEvent + wheezing + handball +
height + appleWalkingSteadinessEvent + lowerBackPain + hiking +
bodyMass + mindfulSession + headache + hockey +
bodyMassIndex + sleepAnalysis + memoryLapse + hunting +
leanBodyMass + toothbrushingEvent + moodChanges + lacrosse +
bodyFatPercentage + handwashingEvent + lossOfSmell + martialArts +
waistCircumference + + lossOfTaste + mindAndBody +
appleSleepingWristTemperature + + runnyNose + paddleSports +
basalBodyTemperature + + soreThroat + play +
environmentalAudioExposure + + sinusCongestion + preparationAndRecovery +
headphoneAudioExposure + + breastPain + racquetball +
heartRate + + pelvicPain + rowing +
restingHeartRate + + vaginalDryness + rugby +
walkingHeartRateAverage + + acne + running +
heartRateVariabilitySDNN + + drySkin + sailing +
heartRateRecoveryOneMinute + + hairLoss + skatingSports +
atrialFibrillationBurden + + nightSweats + snowSports +
oxygenSaturation + + sleepChanges + soccer +
bodyTemperature + + bladderIncontinence + softball +
bloodPressureDiastolic + + + squash +
bloodPressureSystolic + + + stairClimbing +
respiratoryRate + + + surfingSports +
bloodGlucose + + + swimming +
electrodermalActivity + + + tableTennis +
forcedExpiratoryVolume1 + + + tennis +
forcedVitalCapacity + + + trackAndField +
inhalerUsage + + + traditionalStrengthTraining +
insulinDelivery + + + volleyball +
numberOfTimesFallen + + + walking +
peakExpiratoryFlowRate + + + waterFitness +
peripheralPerfusionIndex + + + waterPolo +
dietaryBiotin + + + waterSports +
dietaryCaffeine + + + workout +
dietaryCalcium + + + wrestling +
dietaryCarbohydrates + + + yoga +
dietaryChloride + + + barre +
dietaryCholesterol + + + coreTraining +
dietaryChromium + + + crossCountrySkiing +
dietaryCopper + + + downhillSkiing +
dietaryEnergyConsumed + + + flexibility +
dietaryFatMonounsaturated + + + highIntensityIntervalTraining +
dietaryFatPolyunsaturated + + + jumpRope +
dietaryFatSaturated + + + kickboxing +
dietaryFatTotal + + + pilates +
dietaryFiber + + + snowboarding +
dietaryFolate + + + stairs +
dietaryIodine + + + stepTraining +
dietaryIron + + + wheelchairWalkPace +
dietaryMagnesium + + + wheelchairRunPace +
dietaryManganese + + + taiChi +
dietaryMolybdenum + + + mixedCardio +
dietaryNiacin + + + handCycling +
dietaryPantothenicAcid + + + discSports +
dietaryPhosphorus + + + fitnessGaming +
dietaryPotassium + + + cardioDance +
dietaryProtein + + + cooldown +
dietaryRiboflavin + + + pickleball +
dietarySelenium + + + socialDance +
dietarySodium + + + swimBikeRun +
dietarySugar + + + +
dietaryThiamin + + + +
dietaryVitaminA + + + +
dietaryVitaminB12 + + + +
dietaryVitaminB6 + + + +
dietaryVitaminC + + + +
dietaryVitaminD + + + +
dietaryVitaminE + + + +
dietaryVitaminK + + + +
dietaryWater + + + +
dietaryZinc + + + +
bloodAlcoholContent + + + +
numberOfAlcoholicBeverages + + + +
appleWalkingSteadiness + + + +
sixMinuteWalkTestDistance + + + +
walkingSpeed + + + +
walkingStepLength + + + +
walkingAsymmetryPercentage + + + +
walkingDoubleSupportPercentage + + + +
stairAscentSpeed + + + +
stairDescentSpeed + + + +
uvExposure + + + +
underwaterDepth + + + +
waterTemperature + + + +
workout + + + +
From 7e0697f23de195360a35fd740ecbc0ef8d47603a Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Thu, 30 Mar 2023 14:55:09 +0300 Subject: [PATCH 24/31] documentation fixed --- docs/getMedianStatistic.md | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/docs/getMedianStatistic.md b/docs/getMedianStatistic.md index 5814fa8e..aad4c068 100644 --- a/docs/getMedianStatistic.md +++ b/docs/getMedianStatistic.md @@ -860,7 +860,7 @@ Median counted for intervals between entries from 00:00:00 UTC on 1 January 1970 - + workout @@ -1093,14 +1093,5 @@ Median counted for intervals between entries from 00:00:00 UTC on 1 January 1970 - - workout - - - - - - - - + From e3b8494b0aad90addac7a55f1454178fe6d2cce9 Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Thu, 30 Mar 2023 15:04:41 +0300 Subject: [PATCH 25/31] remove MedianStatisticsDataTypes constants --- index.js | 2 -- src/constants/MedianStatisticsDataTypes.js | 13 ------------- src/constants/index.js | 2 -- 3 files changed, 17 deletions(-) delete mode 100644 src/constants/MedianStatisticsDataTypes.js diff --git a/index.js b/index.js index 809e7053..d848b8e3 100644 --- a/index.js +++ b/index.js @@ -1,7 +1,6 @@ import { Activities, GenericStatisticsAggregators, - MedianStatisticsDataTypes, Observers, Permissions, StatisticsIntervals, @@ -15,7 +14,6 @@ export const HealthKit = Object.assign({}, AppleHealthKit, { Constants: { Activities, GenericStatisticsAggregators, - MedianStatisticsDataTypes, Observers, Permissions, StatisticsIntervals, diff --git a/src/constants/MedianStatisticsDataTypes.js b/src/constants/MedianStatisticsDataTypes.js deleted file mode 100644 index 2f7b3f19..00000000 --- a/src/constants/MedianStatisticsDataTypes.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Apple Health Data Types For Median Statistic - * - * @type {Object} - */ - - import { Activities } from './Activities' - import { Permissions } from './Permissions' - - export const MedianStatisticsDataTypes = { - ...Activities, - ...Permissions - } diff --git a/src/constants/index.js b/src/constants/index.js index 09a90b35..4f88fb49 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -1,5 +1,4 @@ import { Activities } from './Activities' -import { MedianStatisticsDataTypes } from './MedianStatisticsDataTypes' import { Observers } from './Observers' import { Permissions } from './Permissions' import { GenericStatisticsAggregators, StepsStatisticsAggregators } from './StatisticsAggregators'; @@ -9,7 +8,6 @@ import { Units } from './Units' export { Activities, GenericStatisticsAggregators, - MedianStatisticsDataTypes, Observers, Permissions, StatisticsIntervals, From 8b23382c41366c6038dc6d9ca1012ed4d3dc171a Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Thu, 30 Mar 2023 18:44:50 +0300 Subject: [PATCH 26/31] fix for output NSDictionary init --- ...TAppleHealthKit+Methods_MedianStatistics.m | 22 ++++++++++++------- RCTAppleHealthKit/RCTAppleHealthKit+Queries.m | 9 ++++---- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m index aa184089..d52173c5 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m @@ -90,6 +90,12 @@ - (void)statistics_getMedianStatistic:(NSDictionary *)input callback:(RCTRespons NSMutableArray<__kindof HKSample *> *data = results[@"data"]; + if (data == nil) { + hasResults = NO; + NSLog(@"RNHealth getMedianStatistic: An error occured"); + dispatch_semaphore_signal(semaphore); + } + if (([sample isKindOfClass:[HKWorkoutType class]]) && (![@"workout" isEqual:sampleName])) { NSMutableArray<__kindof HKSample *> *dataByActivityType = [NSMutableArray new]; @@ -170,14 +176,14 @@ - (void)statistics_getMedianStatistic:(NSDictionary *)input callback:(RCTRespons NSString *resultStartDateString = [RCTAppleHealthKit buildISO8601StringFromDate:firstSample.startDate]; NSString *resultEndDateString = [RCTAppleHealthKit buildISO8601StringFromDate:lastSample.endDate]; - NSDictionary *response = @{ - @"parameterName" : sampleName, - @"firstEntry" : resultStartDateString, - @"lastEntry" : resultEndDateString, - @"entryCount" : @(resultArray.count), - @"medianSeconds" : medianIntervalInSeconds, - @"medianDays" : medianIntervalInDays, - }; + NSMutableDictionary *response = [NSMutableDictionary dictionary]; + response[@"parameterName"] = sampleName ? sampleName : @""; + response[@"firstEntry"] = resultStartDateString ? resultStartDateString : @""; + response[@"lastEntry"] = resultEndDateString ? resultEndDateString : @""; + response[@"entryCount"] = @(resultArray.count); + response[@"medianSeconds"] = medianIntervalInSeconds ? medianIntervalInSeconds : @"", + response[@"medianDays"] = medianIntervalInDays ? medianIntervalInDays : @""; + [output addObject:response]; } diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Queries.m b/RCTAppleHealthKit/RCTAppleHealthKit+Queries.m index ab60bddb..19ad184d 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Queries.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Queries.m @@ -1198,10 +1198,11 @@ - (void)fetchBatchOfSamples:(HKSampleType *)type NSData *anchorData = [NSKeyedArchiver archivedDataWithRootObject:newAnchor]; NSString *anchorString = [anchorData base64EncodedStringWithOptions:0]; - completion(@{ - @"anchor": anchorString, - @"data": sampleObjects, - }, error); + NSMutableDictionary *response = [NSMutableDictionary dictionary]; + response[@"anchor"] = anchorString ? anchorString : @""; + response[@"data"] = sampleObjects; + + completion(response, error); } }); }; From 260b7f4489ff3a1d093888ef805a7b8d40e5c799 Mon Sep 17 00:00:00 2001 From: mobileapps23 <40164951+mobileapps23@users.noreply.github.com> Date: Thu, 30 Mar 2023 18:56:08 +0300 Subject: [PATCH 27/31] output format numbers fixed for null cases --- .../RCTAppleHealthKit+Methods_MedianStatistics.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m index d52173c5..e1af4186 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m @@ -181,8 +181,8 @@ - (void)statistics_getMedianStatistic:(NSDictionary *)input callback:(RCTRespons response[@"firstEntry"] = resultStartDateString ? resultStartDateString : @""; response[@"lastEntry"] = resultEndDateString ? resultEndDateString : @""; response[@"entryCount"] = @(resultArray.count); - response[@"medianSeconds"] = medianIntervalInSeconds ? medianIntervalInSeconds : @"", - response[@"medianDays"] = medianIntervalInDays ? medianIntervalInDays : @""; + response[@"medianSeconds"] = medianIntervalInSeconds ? medianIntervalInSeconds : [NSNull null]; + response[@"medianDays"] = medianIntervalInDays ? medianIntervalInDays : [NSNull null]; [output addObject:response]; } From 8e627798f6af32800d64ef773eae7713c60d1cf5 Mon Sep 17 00:00:00 2001 From: qkudev Date: Tue, 25 Apr 2023 10:46:26 +0200 Subject: [PATCH 28/31] stat query limit up to 5000, parallel ops up to 10 --- .../RCTAppleHealthKit+Methods_MedianStatistics.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m index e1af4186..a4017831 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m @@ -47,7 +47,7 @@ - (void)statistics_getMedianStatistic:(NSDictionary *)input callback:(RCTRespons } NSOperationQueue *queue = [[NSOperationQueue alloc] init]; - queue.maxConcurrentOperationCount = 5; + queue.maxConcurrentOperationCount = 10; NSOperation *doneOperation = [[NSOperation alloc] init]; [doneOperation setCompletionBlock:^{ @@ -61,7 +61,7 @@ - (void)statistics_getMedianStatistic:(NSDictionary *)input callback:(RCTRespons HKSampleType *sample = validSamples[sampleName]; - int limit = 100; + int limit = 5000; __block HKQueryAnchor *anchor = nil; __block NSMutableArray<__kindof HKSample *> *resultArray = [NSMutableArray new]; __block NSMutableArray<__kindof HKSample *> *samplesFirstByDate = [NSMutableArray new]; From 6f902bb2100cff80ffdfd9f73e4390e4c8ae6754 Mon Sep 17 00:00:00 2001 From: qkudev Date: Thu, 11 May 2023 14:56:47 +0200 Subject: [PATCH 29/31] fixed types for statistics method --- index.d.ts | 157 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 135 insertions(+), 22 deletions(-) diff --git a/index.d.ts b/index.d.ts index 7c59c74e..aa0d4a5d 100644 --- a/index.d.ts +++ b/index.d.ts @@ -471,7 +471,10 @@ declare module 'react-native-health' { getMedianStatistic( options: HealthMedianStatisticsInputOptions, - callback: (err: string, results: Array) => void, + callback: ( + err: string, + results: Array, + ) => void, ): void Constants: Constants @@ -501,11 +504,11 @@ declare module 'react-native-health' { } export interface HealthStatisticsMedianValue { - parameterName: string, - firstEntry: string, - medianSeconds: number, - lastEntry: string, - medianDays: number, + parameterName: string + firstEntry: string + medianSeconds: number + lastEntry: string + medianDays: number entryCount: number } @@ -521,10 +524,10 @@ declare module 'react-native-health' { } export interface HeartbeatSeriesSampleValue extends BaseValue { - heartbeatSeries: ({ + heartbeatSeries: { timeSinceSeriesStart: number precededByGap: boolean - })[] + }[] } export interface HealthUnitOptions { @@ -558,16 +561,21 @@ declare module 'react-native-health' { CUMULATIVE_SUM = 3, } - export type HealthStatisticsCommonAggregatorType = GenericAggregatorsType | AverageAggregatorsType; + export type HealthStatisticsCommonAggregatorType = + | GenericAggregatorsType + | AverageAggregatorsType - export type HealthStatisticsStepsAggregatorType = GenericAggregatorsType | CumulativeAggregatorsType; + export type HealthStatisticsStepsAggregatorType = + | GenericAggregatorsType + | CumulativeAggregatorsType export enum HealthStatisticsIntervalType { MONTH = 0, DAY = 1, } - export interface HealthStatisticsCommonInputOptions extends HealthUnitOptions { + export interface HealthStatisticsCommonInputOptions + extends HealthUnitOptions { aggregator: HealthStatisticsCommonAggregatorType interval?: HealthStatisticsIntervalType startDate?: string @@ -581,8 +589,113 @@ declare module 'react-native-health' { endDate?: string } + export type StatisticKey = + | 'stepCount' + | 'distanceWalkingRunning' + | 'basalEnergyBurned' + | 'activeEnergyBurned' + | 'heartRate' + | 'height' + | 'bodyMassIndex' + | 'basalBodyTemperature' + | 'restingHeartRate' + | 'oxygenSaturation' + | 'bodyTemperature' + | 'bloodPressureDiastolic' + | 'bloodPressureSystolic' + | 'bloodGlucose' + | 'runningGroundContactTime' + | 'runningPower' + | 'runningSpeed' + | 'runningStrideLength' + | 'runningVerticalOscillation' + | 'distanceCycling' + | 'pushCount' + | 'distanceWheelchair' + | 'swimmingStrokeCount' + | 'distanceSwimming' + | 'distanceDownhillSnowSports' + | 'flightsClimbed' + | 'nikeFuel' + | 'appleExerciseTime' + | 'appleMoveTime' + | 'appleStandTime' + | 'vo2Max' + | 'bodyMass' + | 'leanBodyMass' + | 'bodyFatPercentage' + | 'waistCircumference' + | 'appleSleepingWristTemperature' + | 'environmentalAudioExposure' + | 'headphoneAudioExposure' + | 'walkingHeartRateAverage' + | 'heartRateVariabilitySDNN' + | 'heartRateRecoveryOneMinute' + | 'atrialFibrillationBurden' + | 'respiratoryRate' + | 'electrodermalActivity' + | 'forcedExpiratoryVolume1' + | 'forcedVitalCapacity' + | 'inhalerUsage' + | 'insulinDelivery' + | 'numberOfTimesFallen' + | 'peakExpiratoryFlowRate' + | 'peripheralPerfusionIndex' + | 'dietaryBiotin' + | 'dietaryCaffeine' + | 'dietaryCalcium' + | 'dietaryCarbohydrates' + | 'dietaryChloride' + | 'dietaryCholesterol' + | 'dietaryChromium' + | 'dietaryCopper' + | 'dietaryEnergyConsumed' + | 'dietaryFatMonounsaturated' + | 'dietaryFatPolyunsaturated' + | 'dietaryFatSaturated' + | 'dietaryFatTotal' + | 'dietaryFiber' + | 'dietaryFolate' + | 'dietaryIodine' + | 'dietaryIron' + | 'dietaryMagnesium' + | 'dietaryManganese' + | 'dietaryMolybdenum' + | 'dietaryNiacin' + | 'dietaryPantothenicAcid' + | 'dietaryPhosphorus' + | 'dietaryPotassium' + | 'dietaryProtein' + | 'dietaryRiboflavin' + | 'dietarySelenium' + | 'dietarySodium' + | 'dietarySugar' + | 'dietaryThiamin' + | 'dietaryVitaminA' + | 'dietaryVitaminB12' + | 'dietaryVitaminB6' + | 'dietaryVitaminC' + | 'dietaryVitaminD' + | 'dietaryVitaminE' + | 'dietaryVitaminK' + | 'dietaryWater' + | 'dietaryZinc' + | 'bloodAlcoholContent' + | 'numberOfAlcoholicBeverages' + | 'appleWalkingSteadiness' + | 'sixMinuteWalkTestDistance' + | 'walkingSpeed' + | 'walkingStepLength' + | 'walkingAsymmetryPercentage' + | 'walkingDoubleSupportPercentage' + | 'stairAscentSpeed' + | 'stairDescentSpeed' + | 'uvExposure' + | 'underwaterDepth' + | 'waterTemperature' + export interface HealthMedianStatisticsInputOptions { - types: (string[])[] + types: ((StatisticKey)[] | readonly StatisticKey[]); } export interface HKWorkoutQueriedSampleType { @@ -601,12 +714,12 @@ declare module 'react-native-health' { } export interface ElectrocardiogramSampleValue extends BaseValue { - classification: ElectrocardiogramClassification, - averageHeartRate: number, - samplingFrequency: number, - device: string, - algorithmVersion: number, - voltageMeasurements: (number[])[] + classification: ElectrocardiogramClassification + averageHeartRate: number + samplingFrequency: number + device: string + algorithmVersion: number + voltageMeasurements: number[][] } export interface HealthValueOptions extends HealthUnitOptions { @@ -654,10 +767,10 @@ declare module 'react-native-health' { } export interface HealthClinicalRecord extends BaseValue { - sourceName: string, - sourceId: string, - displayName: string, - fhirData: any, + sourceName: string + sourceId: string + displayName: string + fhirData: any } /* Health Constants */ From 565185387b2b9006551fd8464489e60b1bd99503 Mon Sep 17 00:00:00 2001 From: qkudev Date: Thu, 11 May 2023 15:09:25 +0200 Subject: [PATCH 30/31] 1.16.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 76f0ccb3..491b5a81 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-health", - "version": "1.15.1", + "version": "1.16.0", "description": "A React Native package to interact with Apple HealthKit", "main": "index.js", "repository": { From 6ed3cfd3b365567746ace8cc831265b9d7eb7ab4 Mon Sep 17 00:00:00 2001 From: qkudev Date: Thu, 18 May 2023 14:28:27 +0200 Subject: [PATCH 31/31] copyrights fix --- .../RCTAppleHealthKit+Methods_MedianStatistics.h | 7 ------- .../RCTAppleHealthKit+Methods_MedianStatistics.m | 7 ------- .../RCTAppleHealthKit+TypesForMedianStatistic.h | 7 ------- .../RCTAppleHealthKit+TypesForMedianStatistic.m | 7 ------- 4 files changed, 28 deletions(-) diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.h b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.h index 2e6f9f22..6c78a4ee 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.h +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.h @@ -1,10 +1,3 @@ -// -// RCTAppleHealthKit+Methods_MedianStatistics.h -// RCTAppleHealthKit -// -// Created by Anastasia Mishur on 14.03.23. -// - #import "RCTAppleHealthKit.h" @interface RCTAppleHealthKit (Methods_MedianStatistics) diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m index a4017831..52902d28 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit+Methods_MedianStatistics.m @@ -1,10 +1,3 @@ -// -// RCTAppleHealthKit+Methods_MedianStatistics.m -// RCTAppleHealthKit -// -// Created by Anastasia Mishur on 14.03.23. -// - #import "RCTAppleHealthKit+Methods_MedianStatistics.h" #import "RCTAppleHealthKit+TypesForMedianStatistic.h" #import "RCTAppleHealthKit+Queries.h" diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+TypesForMedianStatistic.h b/RCTAppleHealthKit/RCTAppleHealthKit+TypesForMedianStatistic.h index 681264cc..6c50f8f7 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+TypesForMedianStatistic.h +++ b/RCTAppleHealthKit/RCTAppleHealthKit+TypesForMedianStatistic.h @@ -1,10 +1,3 @@ -// -// RCTAppleHealthKit+TypesForMedianStatistic.h -// RNAppleHealthKit -// -// Created by Anastasia Mishur on 22.03.23. -// - #import "RCTAppleHealthKit.h" @interface RCTAppleHealthKit (TypesForMedianStatistic) diff --git a/RCTAppleHealthKit/RCTAppleHealthKit+TypesForMedianStatistic.m b/RCTAppleHealthKit/RCTAppleHealthKit+TypesForMedianStatistic.m index 5df30d0f..d9e4ff7e 100644 --- a/RCTAppleHealthKit/RCTAppleHealthKit+TypesForMedianStatistic.m +++ b/RCTAppleHealthKit/RCTAppleHealthKit+TypesForMedianStatistic.m @@ -1,10 +1,3 @@ -// -// RCTAppleHealthKit+TypesForMedianStatistic.m -// RNAppleHealthKit -// -// Created by Anastasia Mishur on 22.03.23. -// - #import "RCTAppleHealthKit+TypesForMedianStatistic.h" #import "RCTAppleHealthKit+TypesAndPermissions.h"