// // RCTAppleHealthKit.m // RCTAppleHealthKit // // Created by Greg Wilson on 2016-06-26. // Copyright © 2016 Greg Wilson. All rights reserved. // #import "RCTAppleHealthKit.h" #import "RCTAppleHealthKit+Queries.h" #import "RCTAppleHealthKit+TypesAndPermissions.h" #import "RCTAppleHealthKit+Utils.h" @implementation RCTAppleHealthKit RCT_EXPORT_MODULE(); RCT_EXPORT_METHOD(isAvailable:(RCTResponseSenderBlock)callback) { [self isHealthKitAvailable:callback]; } RCT_EXPORT_METHOD(initHealthKit:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback) { [self initializeHealthKit:input callback:callback]; } RCT_EXPORT_METHOD(getCurrentWeight:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback) { [self getHealthKitUserWeight:input callback:callback]; } RCT_EXPORT_METHOD(saveWeight:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback) { [self saveHealthKitUserWeight:input callback:callback]; } RCT_EXPORT_METHOD(getStepCountForToday:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback) { [self getHealthKitUserStepCount:input callback:callback]; } RCT_EXPORT_METHOD(getInfo:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback) { [self getModuleInfo:input callback:callback]; } - (void)isHealthKitAvailable:(RCTResponseSenderBlock)callback { BOOL isAvailable = NO; if ([HKHealthStore isHealthDataAvailable]) { isAvailable = YES; } callback(@[[NSNull null], @(isAvailable)]); } - (void)initializeHealthKit:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback { self.healthStore = [[HKHealthStore alloc] init]; if ([HKHealthStore isHealthDataAvailable]) { NSSet *writeDataTypes = [self dataTypesToWrite]; NSSet *readDataTypes = [self dataTypesToRead]; // get permissions from input object provided by JS options object argument NSDictionary* permissions =[input objectForKey:@"permissions"]; if(permissions != nil){ NSArray* readPermsArray = [permissions objectForKey:@"read"]; NSArray* writePermsArray = [permissions objectForKey:@"write"]; NSSet* readPerms = [self getReadPermsFromOptions:readPermsArray]; NSSet* writePerms = [self getWritePermsFromOptions:writePermsArray]; if(readPerms != nil) { readDataTypes = readPerms; } if(writePerms != nil) { writeDataTypes = writePerms; } } [self.healthStore requestAuthorizationToShareTypes:writeDataTypes readTypes:readDataTypes completion:^(BOOL success, NSError *error) { if (!success) { NSLog(@"You didn't allow HealthKit to access these read/write data types. In your app, try to handle this error gracefully when a user decides not to provide access. The error was: %@. If you're using a simulator, try it on a device.", error); callback(@[RCTMakeError(@"You didn't allow HealthKit to access these read/write data types. In your app, try to handle this error gracefully when a user decides not to provide access. The error was: %@. If you're using a simulator, try it on a device.", nil, nil)]); return; } else { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ callback(@[[NSNull null], @true]); }); } }]; } else { callback(@[RCTMakeError(@"HealthKit not available....", nil, nil)]); } } - (void)getHealthKitUserWeight:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback { // NSMassFormatter *massFormatter = [[NSMassFormatter alloc] init]; // massFormatter.unitStyle = NSFormattingUnitStyleLong; // NSMassFormatterUnit weightFormatterUnit = NSMassFormatterUnitPound; // NSString *weightUnitString = [massFormatter unitStringFromValue:10 unit:weightFormatterUnit]; // NSString *localizedWeightUnitDescriptionFormat = NSLocalizedString(@"Weight (%@)", nil); // Query to get the user's latest weight, if it exists. HKQuantityType *weightType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass]; [self fetchMostRecentQuantitySampleOfType:weightType predicate:nil completion:^(HKQuantity *mostRecentQuantity, NSError *error) { if (!mostRecentQuantity) { NSLog(@"Either an error occured fetching the user's weight information or none has been stored yet. In your app, try to handle this gracefully."); callback(@[RCTMakeError(@"Either an error occured fetching the user's weight information or none has been stored yet. In your app, try to handle this gracefully.", nil, nil)]); } else { // Determine the weight in the required unit. HKUnit *weightUnit = [HKUnit poundUnit]; double usersWeight = [mostRecentQuantity doubleValueForUnit:weightUnit]; callback(@[[NSNull null], @(usersWeight)]); } }]; } - (void)saveHealthKitUserWeight:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback { double weight= [[input objectForKey:@"weight"] doubleValue]; HKUnit *poundUnit = [HKUnit poundUnit]; HKQuantity *weightQuantity = [HKQuantity quantityWithUnit:poundUnit doubleValue:weight]; HKQuantityType *weightType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass]; NSDate *now = [NSDate date]; HKQuantitySample *weightSample = [HKQuantitySample quantitySampleWithType:weightType quantity:weightQuantity startDate:now endDate:now]; [self.healthStore saveObject:weightSample withCompletion:^(BOOL success, NSError *error) { if (!success) { NSLog(@"An error occured saving the weight sample %@. In your app, try to handle this gracefully. The error was: %@.", weightSample, error); callback(@[RCTMakeError(@"An error occured saving the weight sample", nil, nil)]); return; // abort(); } callback(@[[NSNull null], @(weight)]); }]; } - (void)getHealthKitUserStepCount:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback { HKQuantityType *stepCountType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]; HKUnit *stepsUnit = [HKUnit countUnit]; [self fetchSumOfSamplesTodayForType:stepCountType unit:stepsUnit completion:^(double totalSteps, NSError *error) { if (!totalSteps) { NSLog(@"Either an error occured fetching the user's step count information or none has been stored yet. In your app, try to handle this gracefully."); callback(@[RCTMakeError(@"Either an error occured fetching the user's step count information or none has been stored yet. In your app, try to handle this gracefully.", nil, nil)]); return; } callback(@[[NSNull null], @(totalSteps)]); }]; } - (void)getModuleInfo:(NSDictionary *)input callback:(RCTResponseSenderBlock)callback { callback(@[[NSNull null], @"ReactNative Apple HealthKit Native Module. Created By Greg Wilson."]); } @end