Monday, November 3, 2014

iOS: Health App and HealthKit Part:- 3

In this post i will discuss about how to create a HealthKit Application , By which you can share your Health and Fitness information to Health application or retrieve data from it.

If you do not know what is HealthKit and Health application then please check my blogs 



Health App and HealthKit Part:- 1  and Health App and HealthKit Part:- 2

Lets start with our example.
RequirementsXcode 6 and iOS 8 

Example:


1) Create an Application id which supports HealthKit.


From developer.apple.com you need to create an App ID , and you can check HealthKit feature  same as you do with Push Notifications, In App Purchase.





Now you have to create provisioning profile which supports this application. You have to your application with this provisioning profile.

2) An Entitlements.plist file

An Entitlements.plist with  com.apple.developer.healthkit property which has Boolean type and Set it to Yes.

3) Change in Info.plist file

In your Info.plist file UIRequiredDeviceCapabilities key you need to add entry called healthkit with String type.

4) Coding Part
  • Add healthKit Framework to your project.
  • Import HealthKit in your controller by 
    @import HealthKit
  • Authentication: Open an HealthKit view which contains reading and writing permissions.


- (void)authentication
{
    self.healthStore = [[HKHealthStore alloc] init];
    
    
    if ([HKHealthStore isHealthDataAvailable]) {
        NSSet *writeDataTypes = [self dataTypesToWrite];
        NSSet *readDataTypes = [self dataTypesToRead];
        
        [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);
                
                return;
            }
            
            dispatch_async(dispatch_get_main_queue(), ^{
                // Update the user interface based on the current user's health information.
            });
        }];
    }


}
  • Where read and write data types are

- (NSSet *)dataTypesToWrite {
    
        HKQuantityType *heightType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeight];

        HKQuantityType *weightType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass];

    
        return [NSSet setWithObjects: heightType, weightType, nil];

}

// Returns the types of data that Fit wishes to read from HealthKit.
- (NSSet *)dataTypesToRead {
        HKQuantityType *heightType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeight];

        HKQuantityType *weightType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass];

        HKCharacteristicType *birthdayType = [HKObjectType characteristicTypeForIdentifier:HKCharacteristicTypeIdentifierDateOfBirth];

        HKCharacteristicType *biologicalSexType = [HKObjectType characteristicTypeForIdentifier:HKCharacteristicTypeIdentifierBiologicalSex];

    
        return [NSSet setWithObjects: heightType, weightType, birthdayType, biologicalSexType, nil];

}




You can add ass many quantitypes here , For making example simpler i just considered two to four.


By Calling this authentication method it will open below screen.




This screen contains read and write quantity types which we request. You can access in in your applications by setting them ON.
  • Now we need to write data to Health Application. 

- (IBAction)storeWeight:(id)sender
{
    HKQuantityType *weightType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass];

    
    HKUnit *poundUnit = [HKUnit poundUnit];

    HKQuantity *weightQuantity = [HKQuantity quantityWithUnit:poundUnit doubleValue:100];

    
    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(error) {

            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"error" message:error.description delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];

            [alert show];

        }

        else{

            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Weight added to health app" message:nil delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];

            [alert show];

        }
    }];
    
}


So here we created a Sample with quantity type weight with pound Unit. and we are wring 100 pound value in to it.

So by the method saveObject:weightSample you can write any quantity to your healthstore and here we are writing Weight to it and it is 100 in our case.



  • For reading Data from HealthKit

- (IBAction)getWeight:(id)sender
{
    HKQuantityType *weightType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass];

    
    // Since we are interested in retrieving the user's latest sample
    // we sort the samples in descending order by end date
    // and set the limit to 1
    // We are not filtering the data, and so the predicate is set to nil.
    NSSortDescriptor *timeSortDescriptor = [[NSSortDescriptor alloc] initWithKey:HKSampleSortIdentifierEndDate ascending:NO];
    
    // construct the query & since we are not filtering the data the predicate is set to nil
    HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:weightType predicate:nil limit:1 sortDescriptors:@[timeSortDescriptor] resultsHandler:^(HKSampleQuery *query, NSArray *results, NSError *error) {
        
        if(error)
        {
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"error" message:error.description delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
            [alert show];

        }
        // if there is a data point, dispatch to the main queue
        if (results) {
            dispatch_async(dispatch_get_main_queue(), ^{
                HKQuantitySample *quantitySample = results.firstObject;
                
                // pull out the quantity from the sample
                HKQuantity *quantity = quantitySample.quantity;
                
                HKUnit *weightUnit = [HKUnit poundUnit];
                double usersWeight = [quantity doubleValueForUnit:weightUnit];
                NSString *str = [NSString stringWithFormat:@"%@ lbs", [NSNumberFormatter localizedStringFromNumber:@(usersWeight) numberStyle:NSNumberFormatterNoStyle]];
                UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Success" message:str delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
                [alert show];

            });
        }
    }];
    
    // do not forget to execute the query after its constructed
    [self.healthStore executeQuery:query];


}

It will read latest weight from your Health Application.

You can download source code here.