HealthKit

Demo 展示效果

recordTime2.gif

前言

随着人们对健康的重视,移动端两大巨头Apple和Google都推出了各自的健康库 Apple Health , Google Fit ,它们集成大部分健康中所用到的数据类型,各个应用根据自己所擅长的领域写入相关健康健身数据,或共享其库中其他健康数据,以达各尽所长,数据共享!

简述

HealthKit框架提供了一个结构,应用可以使用它来分享健康和健身数据。HealthKit管理从不同来源获得的数据,并根据用户的偏好设置,自动将不同来源的所有数据合并起来。应用还可以获取每个来源的原始数据,然后执行自己的数据合并。

HealthKit另外提供了一个应用来帮助管理用户的健康数据。健康应用为用户展示HealthKit的数据。用户可以使用健康应用来查看、添加、删除或者管理其全部的健康和健身数据。用户还可以编辑每种数据类型的分享权限。

HealthKit和健康应用在iPad上都不可用。

隐私

由于健康数据可能是敏感的,HealthKit通过精确控制哪些信息允许应用读取,从而让用户可以控制这些数据。用户必须明确设置每个应用在HealthKit存储中读写的权限。用户可以单独为每种数据类型设置准许或拒绝的权限。例如,用户可以允许你的应用读取计步数据,但是不允许读取用户心率数据。为了防止可能的信息泄露,应用在不调用相关访问接口时,是不知道它是否被禁止读取数据的。

HealthKit的数据不会保存在iCloud中,也不会在多设备间同步。这些数据只会保存在用户的本地设备中。为了安全考虑,当设备没有解锁时,HealthKit存储的数据是加密的。

另外,你的应用如果主要不是提供健康或健身服务的话,那就不能调用HealthKit的API。如果你的应用提供健康和健身服务,就必须要在App Store相关应用简介和应用界面上明确的表明。

使用HealthKit特别注意

  1. 你的应用不应该将HealthKit收集的数据用于广告或类似的服务。注意,在使用HealthKit框架应用中可以插播广告,但是你不能使用HealthKit中的数据来服务广告。

  2. 在没有用户的明确允许下,你不能向第三方展示任何HealthKit收集的数据。即使用户允许,你也只能向提供健康或健身服务的第三方展示这些数据。

  3. 你不能将HealthKit收集的数据出售给广告平台、数据代理人或者信息经销商。

  4. 如果用户允许,你可以将HealthKit数据共享给第三方用于医学研究。注意是用户允许

  5. 你必须明确说明,你和你的应用会怎样使用用户的HealthKit数据。

应用中使用了HealthKit 上 App Store 特别注意

  1. 一定要添加隐私政策网址链接,并注明健康数据使用的隐私相关条例。例如:

    • 在App里您设置身高、体重时,根据您之前是否允许授权权限,XXX将依据您给的权限是否把信息写入苹果健康应用。
    • 在App里同步计步、睡眠、心率数据时,根据您之前是否允许授权权限,XXX将依据您给的权限是否把信息写入苹果健康应用。
  2. 应用介绍中一定要注明:此版本支持你使用Apple健康应用程序

HealthKit设计目标

HealthKit是用来在应用间以一种有意义的方式共享数据。为了达到这点,框架限制只能使用预先定义好的数据类型和单位。这些限制保证了其他应用能理解这些数据是什么意思,以及怎样使用。因此,开发者不能创建自定义数据类型和单位。而HealthKit尽量会提供一个完整的数据类型和单位。

HealthKit 存储理念

框架大量使用了子类化,在相似的类间创建层级关系。通常这些类间都有一些细微但是重要的差别。还有不少和它相关的类,需要正确搭配,才能一起工作。存储在HealthKit中的数据都是由对象和对象所属类型组成,这个概念一定要刻入脑海,你才能理解整个存储结构。所有对象都是基于HKObject,所有对象所属的类型都是基于HKObjectType。下面简单介绍下这两个类:

  • HKObject我们不能直接使用,而是使用它的子类。子类有:

  • HKObject 主要分为两类:特征和样本。特征对象代表一些基本不变的数据。例如:用户的生日、血型和生理性别,肤色。你的应用不能写入特征数据。用户必须通过健康应用来输入或者修改这些数据。

    • 样本对象是某个特定时间断的数据。所有的样本对象都是HKSample的子类。它们都有下列属性:
      • sampleType: 样本类型。例如:一个睡眠分析样本、一个身高样本或者一个计步样本。
      • startDate : 样本的开始时间。
      • endDate : 样本的结束时间。
  • HKObject 所有对象都是不可变的(除非修改了对象来源),创建对象时需设置对象的相关属性。所有对象都有相同的属性。如下所示:

    • 唯一的标识符UUID
    • 数据来源source 9.0版本后用sourceRevision
    • device生成这个对象数据的设备。
    • Metadata用来描述对象的额外信息,是NSDictionary类型,其中Key都为NSString类型,Value可以为NSString,NSNumber,NSDate类型。其中Key可以为系统预定义的也可以自定义。系统预定义的Key:

NSString * const HKMetadataKeyDeviceSerialNumber;
NSString * const HKMetadataKeyBodyTemperatureSensorLocation;
NSString * const HKMetadataKeyHeartRateSensorLocation;
NSString * const HKMetadataKeyFoodType;
NSString * const HKMetadataKeyUDIDeviceIdentifier;
NSString * const HKMetadataKeyUDIProductionIdentifier;
NSString * const HKMetadataKeyDigitalSignature;
NSString * const HKMetadataKeyExternalUUID;
NSString * const HKMetadataKeyTimeZone;
NSString * const HKMetadataKeyDeviceName;
NSString * const HKMetadataKeyDeviceManufacturerName;
NSString * const HKMetadataKeyWasTakenInLab;
NSString * const HKMetadataKeyReferenceRangeLowerLimit;
NSString * const HKMetadataKeyReferenceRangeUpperLimit;
NSString * const HKMetadataKeyWasUserEntered;
NSString * const HKMetadataKeyWorkoutBrandName;
NSString * const HKMetadataKeyGroupFitness;
NSString * const HKMetadataKeyIndoorWorkout;
NSString * const HKMetadataKeyCoachedWorkout;
NSString * const HKMetadataKeySexualActivityProtectionUsed;
NSString * const HKMetadataKeyMenstrualCycleStart;
```

+ (nullable HKQuantityType *)quantityTypeForIdentifier:(NSString *)identifier;
+ (nullable HKCategoryType *)categoryTypeForIdentifier:(NSString *)identifier;
+ (nullable HKCharacteristicType *)characteristicTypeForIdentifier:(NSString *)identifier;
+ (nullable HKCorrelationType *)correlationTypeForIdentifier:(NSString *)identifier;
  • 系统预定义类型的Identifiers有:
/*--------------------------------*/
/*   HKQuantityType Identifiers   */
/*--------------------------------*/

// Body Measurements
HK_EXTERN NSString * const HKQuantityTypeIdentifierBodyMassIndex NS_AVAILABLE_IOS(8_0);             // Scalar(Count),               Discrete
HK_EXTERN NSString * const HKQuantityTypeIdentifierBodyFatPercentage NS_AVAILABLE_IOS(8_0);         // Scalar(Percent, 0.0 - 1.0),  Discrete
HK_EXTERN NSString * const HKQuantityTypeIdentifierHeight NS_AVAILABLE_IOS(8_0);                    // Length,                      Discrete
HK_EXTERN NSString * const HKQuantityTypeIdentifierBodyMass NS_AVAILABLE_IOS(8_0);                  // Mass,                        Discrete
HK_EXTERN NSString * const HKQuantityTypeIdentifierLeanBodyMass NS_AVAILABLE_IOS(8_0);              // Mass,                        Discrete

// Fitness
HK_EXTERN NSString * const HKQuantityTypeIdentifierStepCount NS_AVAILABLE_IOS(8_0);                 // Scalar(Count),               Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDistanceWalkingRunning NS_AVAILABLE_IOS(8_0);    // Length,                      Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDistanceCycling NS_AVAILABLE_IOS(8_0);           // Length,                      Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierBasalEnergyBurned NS_AVAILABLE_IOS(8_0);         // Energy,                      Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierActiveEnergyBurned NS_AVAILABLE_IOS(8_0);        // Energy,                      Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierFlightsClimbed NS_AVAILABLE_IOS(8_0);            // Scalar(Count),               Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierNikeFuel NS_AVAILABLE_IOS(8_0);                  // Scalar(Count),               Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierAppleExerciseTime HK_AVAILABLE_IOS_WATCHOS(9_3, 2_2);    // Time                         Cumulative

// Vitals
HK_EXTERN NSString * const HKQuantityTypeIdentifierHeartRate NS_AVAILABLE_IOS(8_0);                 // Scalar(Count)/Time,          Discrete
HK_EXTERN NSString * const HKQuantityTypeIdentifierBodyTemperature NS_AVAILABLE_IOS(8_0);           // Temperature,                 Discrete
HK_EXTERN NSString * const HKQuantityTypeIdentifierBasalBodyTemperature NS_AVAILABLE_IOS(9_0);      // Basal Body Temperature,      Discrete
HK_EXTERN NSString * const HKQuantityTypeIdentifierBloodPressureSystolic NS_AVAILABLE_IOS(8_0);     // Pressure,                    Discrete
HK_EXTERN NSString * const HKQuantityTypeIdentifierBloodPressureDiastolic NS_AVAILABLE_IOS(8_0);    // Pressure,                    Discrete
HK_EXTERN NSString * const HKQuantityTypeIdentifierRespiratoryRate NS_AVAILABLE_IOS(8_0);           // Scalar(Count)/Time,          Discrete

// Results
HK_EXTERN NSString * const HKQuantityTypeIdentifierOxygenSaturation NS_AVAILABLE_IOS(8_0);          // Scalar (Percent, 0.0 - 1.0,  Discrete
HK_EXTERN NSString * const HKQuantityTypeIdentifierPeripheralPerfusionIndex NS_AVAILABLE_IOS(8_0);  // Scalar(Percent, 0.0 - 1.0),  Discrete
HK_EXTERN NSString * const HKQuantityTypeIdentifierBloodGlucose NS_AVAILABLE_IOS(8_0);              // Mass/Volume,                 Discrete
HK_EXTERN NSString * const HKQuantityTypeIdentifierNumberOfTimesFallen NS_AVAILABLE_IOS(8_0);       // Scalar(Count),               Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierElectrodermalActivity NS_AVAILABLE_IOS(8_0);     // Conductance,                 Discrete
HK_EXTERN NSString * const HKQuantityTypeIdentifierInhalerUsage NS_AVAILABLE_IOS(8_0);              // Scalar(Count),               Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierBloodAlcoholContent NS_AVAILABLE_IOS(8_0);       // Scalar(Percent, 0.0 - 1.0),  Discrete
HK_EXTERN NSString * const HKQuantityTypeIdentifierForcedVitalCapacity NS_AVAILABLE_IOS(8_0);       // Volume,                      Discrete
HK_EXTERN NSString * const HKQuantityTypeIdentifierForcedExpiratoryVolume1 NS_AVAILABLE_IOS(8_0);   // Volume,                      Discrete
HK_EXTERN NSString * const HKQuantityTypeIdentifierPeakExpiratoryFlowRate NS_AVAILABLE_IOS(8_0);    // Volume/Time,                 Discrete

// Nutrition
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryFatTotal NS_AVAILABLE_IOS(8_0);           // Mass,   Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryFatPolyunsaturated NS_AVAILABLE_IOS(8_0); // Mass,   Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryFatMonounsaturated NS_AVAILABLE_IOS(8_0); // Mass,   Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryFatSaturated NS_AVAILABLE_IOS(8_0);       // Mass,   Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryCholesterol NS_AVAILABLE_IOS(8_0);        // Mass,   Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietarySodium NS_AVAILABLE_IOS(8_0);             // Mass,   Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryCarbohydrates NS_AVAILABLE_IOS(8_0);      // Mass,   Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryFiber NS_AVAILABLE_IOS(8_0);              // Mass,   Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietarySugar NS_AVAILABLE_IOS(8_0);              // Mass,   Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryEnergyConsumed NS_AVAILABLE_IOS(8_0);     // Energy, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryProtein NS_AVAILABLE_IOS(8_0);            // Mass,   Cumulative

HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryVitaminA NS_AVAILABLE_IOS(8_0);           // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryVitaminB6 NS_AVAILABLE_IOS(8_0);          // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryVitaminB12 NS_AVAILABLE_IOS(8_0);         // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryVitaminC NS_AVAILABLE_IOS(8_0);           // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryVitaminD NS_AVAILABLE_IOS(8_0);           // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryVitaminE NS_AVAILABLE_IOS(8_0);           // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryVitaminK NS_AVAILABLE_IOS(8_0);           // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryCalcium NS_AVAILABLE_IOS(8_0);            // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryIron NS_AVAILABLE_IOS(8_0);               // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryThiamin NS_AVAILABLE_IOS(8_0);            // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryRiboflavin NS_AVAILABLE_IOS(8_0);         // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryNiacin NS_AVAILABLE_IOS(8_0);             // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryFolate NS_AVAILABLE_IOS(8_0);             // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryBiotin NS_AVAILABLE_IOS(8_0);             // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryPantothenicAcid NS_AVAILABLE_IOS(8_0);    // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryPhosphorus NS_AVAILABLE_IOS(8_0);         // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryIodine NS_AVAILABLE_IOS(8_0);             // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryMagnesium NS_AVAILABLE_IOS(8_0);          // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryZinc NS_AVAILABLE_IOS(8_0);               // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietarySelenium NS_AVAILABLE_IOS(8_0);           // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryCopper NS_AVAILABLE_IOS(8_0);             // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryManganese NS_AVAILABLE_IOS(8_0);          // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryChromium NS_AVAILABLE_IOS(8_0);           // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryMolybdenum NS_AVAILABLE_IOS(8_0);         // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryChloride NS_AVAILABLE_IOS(8_0);           // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryPotassium NS_AVAILABLE_IOS(8_0);          // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryCaffeine NS_AVAILABLE_IOS(8_0);           // Mass, Cumulative
HK_EXTERN NSString * const HKQuantityTypeIdentifierDietaryWater NS_AVAILABLE_IOS(9_0);              // Volume, Cumulative

HK_EXTERN NSString * const HKQuantityTypeIdentifierUVExposure NS_AVAILABLE_IOS(9_0);                // Scalar (Count), Discrete

/*--------------------------------*/
/*   HKCategoryType Identifiers   */
/*--------------------------------*/

HK_EXTERN NSString * const HKCategoryTypeIdentifierSleepAnalysis NS_AVAILABLE_IOS(8_0);             // HKCategoryValueSleepAnalysis
HK_EXTERN NSString * const HKCategoryTypeIdentifierAppleStandHour NS_AVAILABLE_IOS(9_0);            // HKCategoryValueAppleStandHour
HK_EXTERN NSString * const HKCategoryTypeIdentifierCervicalMucusQuality NS_AVAILABLE_IOS(9_0);      // HKCategoryValueCervicalMucusQuality
HK_EXTERN NSString * const HKCategoryTypeIdentifierOvulationTestResult NS_AVAILABLE_IOS(9_0);       // HKCategoryValueOvulationTestResult
HK_EXTERN NSString * const HKCategoryTypeIdentifierMenstrualFlow NS_AVAILABLE_IOS(9_0);             // HKCategoryValueMenstrualFlow
HK_EXTERN NSString * const HKCategoryTypeIdentifierIntermenstrualBleeding NS_AVAILABLE_IOS(9_0);    // (Spotting) HKCategoryValue
HK_EXTERN NSString * const HKCategoryTypeIdentifierSexualActivity NS_AVAILABLE_IOS(9_0);            // HKCategoryValue


/*--------------------------------------*/
/*   HKCharacteristicType Identifiers   */
/*--------------------------------------*/

HK_EXTERN NSString * const HKCharacteristicTypeIdentifierBiologicalSex NS_AVAILABLE_IOS(8_0); // NSNumber (HKCharacteristicBiologicalSex)
HK_EXTERN NSString * const HKCharacteristicTypeIdentifierBloodType NS_AVAILABLE_IOS(8_0);     // NSNumber (HKCharacteristicBloodType)
HK_EXTERN NSString * const HKCharacteristicTypeIdentifierDateOfBirth NS_AVAILABLE_IOS(8_0);   // NSDate
HK_EXTERN NSString * const HKCharacteristicTypeIdentifierFitzpatrickSkinType NS_AVAILABLE_IOS(9_0); // HKFitzpatrickSkinType

/*-----------------------------------*/
/*   HKCorrelationType Identifiers   */
/*-----------------------------------*/

HK_EXTERN NSString * const HKCorrelationTypeIdentifierBloodPressure NS_AVAILABLE_IOS(8_0);
HK_EXTERN NSString * const HKCorrelationTypeIdentifierFood NS_AVAILABLE_IOS(8_0);

/*------------------------------*/
/*   HKWorkoutType Identifier   */
/*------------------------------*/

HK_EXTERN NSString * const HKWorkoutTypeIdentifier NS_AVAILABLE_IOS(8_0);

NS_ASSUME_NONNULL_END

如何使用

  • 创建一个工程取名为: HealthKit
  • Xcode8.0 , iOS 10.0后需要在Info.plist文件中添加读写说明,是否感觉似曾相识,其实它和使用定位功能时,需要在Info.plist中添加说明一个道理。(Demo 中的说明只是告诉你相关描述对应的读取或写入操作而已,具体描述自己根据应用实际情况斟酌描述)如下图所示:
屏幕快照 2016-09-24 12.22.54.png
  • TAGETS->Capabilities 打开->HealthKit如下图所示:

屏幕快照 2016-09-20 22.12.44.png

这时工程将会自动将HealthKit.framework加入工程。

  • 创建一个管理我们HealthKit相关操作的类:ZHHealthManager里面包含请求访问HealthKit库以及相关读写操作。

    • ZHHealthManager.h文件相关方法

#import <Foundation/Foundation.h>
#import <HealthKit/HealthKit.h>

typedef void (^ZHHealthKitFinishBlock) (BOOL success,NSError *error);
typedef void (^ZHHealthKitIntegerValueBlock)(NSInteger value, NSError *error);

@interface ZHHealthManager : NSObject
@property (nonatomic) HKHealthStore * healthStore;

+(ZHHealthManager *)shareZHHealthManager;


/**
*  request Authorization To Share Data in HealthKit
*
*  @param finish block
*/
-(void)requestAuthorizationToShareWithCompletion:(ZHHealthKitFinishBlock)finish;


/**
*  Read User Age
*
*  @param finish finish block.
*/
-(void)readUsersAgeWithFinish:(ZHHealthKitIntegerValueBlock)finish;


/**
*  write height data into HealthKit
*
*  @param height height `cm`
*  @param unit   unit Option
*  @param finish block
*/
-(void)saveHeightIntoHealthStore:(double)height withCompletion:(ZHHealthKitFinishBlock)finish;


/**
*  write weight data into HealthKit
*
*  @param weight weight `kg`
*  @param unit   unit option
*  @param finish finishBlock
*/
-(void)saveWeightIntoHealthStore:(double)weight withCompletion:(ZHHealthKitFinishBlock)finish;


/**
*  save stepcount into HealthKit
*
*  @param steps     steps
*  @param startDate startDate
*  @param endDate   endDate
*  @param finish    Block
*/
-(void)saveStepCount:(NSInteger)steps startTime:(NSDate *)startDate endTime:(NSDate *)endDate withCompletion:(ZHHealthKitFinishBlock)finish;


/**
*  save walk distance into healthKit
*
*  @param walkDistance walk distance
*  @param startDate    startDate
*  @param endDate      endDate
*  @param finish       block
*/
-(void)saveWalkDistance:(double)walkDistance startTime:(NSDate *)startDate endTime:(NSDate *)endDate withCompletion:(ZHHealthKitFinishBlock)finish;


/**
*  save active Energy burn calories into healthKit
*
*  @param calories  calories
*  @param startDate startDate
*  @param endDate   endDate
*  @param finish    block
*/
-(void)saveActiveEnergyBurnCalories:(double)calories startTime:(NSDate *)startDate endTime:(NSDate *)endDate withCompletion:(ZHHealthKitFinishBlock)finish;


/**
*  save heartRate into HealthKit
*
*  @param heartRate heartRate
*  @param finish    block
*/
-(void)saveHeartRate:(NSInteger)heartRate withCompletion:(ZHHealthKitFinishBlock)finish;


/**
*  save sleep data into HealthKit
*
*  @param startDate start time
*  @param endDate   end time
*  @param finish    finish block
*/
-(void)saveSleepWithstartTime:(NSDate *)startDate endTime:(NSDate *)endDate withCompletion:(ZHHealthKitFinishBlock)finish;
@end

方法调用

  • 首先我们需要把自己想要读或写的相关数据类型写明。
#pragma mark - Health Kit TypesToWrite
-(NSSet *)dataTypesToWrite
{
   HKQuantityType *stepCountQuantityType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];
   HKQuantityType *walkDistanceQuantityType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning];
   HKQuantityType *activeEnergyBurnQuantityType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierActiveEnergyBurned];
   HKQuantityType *heartQuantityType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate];
   HKCategoryType *sleepCategoryType = [HKCategoryType categoryTypeForIdentifier:HKCategoryTypeIdentifierSleepAnalysis];
   
   HKQuantityType *heightType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeight];
   HKQuantityType *weightType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass];
   
   
   return [NSSet setWithObjects:stepCountQuantityType, walkDistanceQuantityType, activeEnergyBurnQuantityType,sleepCategoryType,heartQuantityType,heightType,weightType, nil];
}

#pragma mark - Health Kit TypesToRead
- (NSSet *)dataTypesToRead {
   HKCharacteristicType *ageTypte = [HKObjectType characteristicTypeForIdentifier:HKCharacteristicTypeIdentifierDateOfBirth];
   return [NSSet setWithObjects:ageTypte, nil];
}
  • 然后申请访问相关读写操作。
-(void)requestAuthorizationToShareWithCompletion:(ZHHealthKitFinishBlock)finish
{
    if ([HKHealthStore isHealthDataAvailable]) {
        NSSet *writeDataTypes = [self dataTypesToWrite];
        NSSet *readDataTypes = [self dataTypesToRead];
        [self.healthStore requestAuthorizationToShareTypes:writeDataTypes readTypes:readDataTypes completion:^(BOOL success, NSError *error){
            if (finish) {
                finish(success,error);
            }
        }];
    }else{
        NSDictionary *userInfo = @{NSLocalizedDescriptionKey: NSLocalizedString(@"健康应用不可用!", @"健康应用不可用!"),NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"Health Kit not available.", @"Health Kit not available."),NSLocalizedRecoverySuggestionErrorKey: NSLocalizedString(@"Have you tried turning it off and on again?", @"Have you tried turning it off and on again?")};
        NSError *error = [NSError errorWithDomain:NSPOSIXErrorDomain code:-10 userInfo:userInfo];
        if (finish) {
            finish(NO,error);
        }
        
        NSLog(@"Health Kit not available");
    }
}

  • 获取权限后进行读或写相关操作,重要记住三点。
  1. 判断系统版本,低于8.0不可用。
  2. 判断设备是否支持HealthKit。[HKHealthStore isHealthDataAvailable]
  3. 判断用户是否对这个类型的进行授权。authorizationStatusForType (基本不可变数据类型除外,例如:生日,性别,血型等)不对授权进行判断,一般不会出问题在进行读写操作时也会有错误提示。但是对数据操作时系统判断更耗时而且有时会出现莫名的错误。
  • 这里举两个例子说明下:
    • 对年龄进行读操作。
    • 对身高进行写操作。

年龄读操作

-(void)readUsersAgeWithFinish:(ZHHealthKitIntegerValueBlock)finish
{
    NSInteger systemVersion = [[UIDevice currentDevice].systemVersion floatValue];
    if (systemVersion <8.0){//系统少于8.0不可用
        return;
    }
    if (![HKHealthStore isHealthDataAvailable])//健康不可用直接返回
    {
        return;
    }
    NSError *error;
    NSDate *dateOfBirth = [self.healthStore dateOfBirthWithError:&error];
    NSInteger age = -1;//年龄没有获取到返回-1
    if (dateOfBirth) {//读取到生日转换成年龄
        NSDate *now = [NSDate date];
        NSDateComponents *ageComponents = [[NSCalendar currentCalendar] components:NSCalendarUnitYear fromDate:dateOfBirth toDate:now options:NSCalendarWrapComponents];
        NSUInteger usersAge = [ageComponents year];
        age = usersAge;
    }
    if (finish) {
        finish(age,error);
    }
}

身高写操作


-(void)saveHeightIntoHealthStore:(double)height withCompletion:(ZHHealthKitFinishBlock)finish
{
    NSInteger systemVersion = [[UIDevice currentDevice].systemVersion floatValue];
    if (systemVersion <8.0){//系统少于8.0不可用
        return;
    }
    if (![HKHealthStore isHealthDataAvailable])//健康不可用直接返回
    {
        return;
    }
    HKQuantityType *weightType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass];
    if ([self.healthStore authorizationStatusForType:weightType] != HKAuthorizationStatusSharingAuthorized) {
        NSLog(@"未经用户允许访问直接返回");
        return;
        
    }

    HKUnit *hkUnit = [HKUnit inchUnit];
    height = height/100;
    hkUnit = [HKUnit meterUnit];
    HKQuantity *heightQuantity = [HKQuantity quantityWithUnit:hkUnit doubleValue:height];
    HKQuantityType *heightType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeight];
    if ([self.healthStore authorizationStatusForType:heightType]) {
        
    }
    NSDate *now = [NSDate date];
    HKQuantitySample *heightSample = [HKQuantitySample quantitySampleWithType:heightType quantity:heightQuantity startDate:now endDate:now];
    [self.healthStore saveObject:heightSample withCompletion:^(BOOL success, NSError *error){
            if (finish) {
                finish(success, error);
            }
        }];

}
  • 当然在进行其他样本操作时,例如:记步,睡眠等等。如果有可能出现重复写入,我们需要先进行判断这段时间内的数据是否已经存入HealthKit。这里会用到查询操作,具体可以参考我Demo中的HKHealthStore+ZHHKExtensions类。

Demo 下载地址

GitHub

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容