HealthKit

Demo 展示效果

recordTime2.gif

前言

隨著人們對健康的重視,移動端兩大巨頭Apple和Google都推出了各自的健康庫 Apple Health , Google Fit ,它們集成大部分健康中所用到的數(shù)據(jù)類型,各個應用根據(jù)自己所擅長的領域寫入相關健康健身數(shù)據(jù),或共享其庫中其他健康數(shù)據(jù),以達各盡所長,數(shù)據(jù)共享!

簡述

HealthKit框架提供了一個結構,應用可以使用它來分享健康和健身數(shù)據(jù)。HealthKit管理從不同來源獲得的數(shù)據(jù),并根據(jù)用戶的偏好設置,自動將不同來源的所有數(shù)據(jù)合并起來。應用還可以獲取每個來源的原始數(shù)據(jù),然后執(zhí)行自己的數(shù)據(jù)合并。

HealthKit另外提供了一個應用來幫助管理用戶的健康數(shù)據(jù)。健康應用為用戶展示HealthKit的數(shù)據(jù)。用戶可以使用健康應用來查看、添加、刪除或者管理其全部的健康和健身數(shù)據(jù)。用戶還可以編輯每種數(shù)據(jù)類型的分享權限。

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

隱私

由于健康數(shù)據(jù)可能是敏感的,HealthKit通過精確控制哪些信息允許應用讀取,從而讓用戶可以控制這些數(shù)據(jù)。用戶必須明確設置每個應用在HealthKit存儲中讀寫的權限。用戶可以單獨為每種數(shù)據(jù)類型設置準許或拒絕的權限。例如,用戶可以允許你的應用讀取計步數(shù)據(jù),但是不允許讀取用戶心率數(shù)據(jù)。為了防止可能的信息泄露,應用在不調(diào)用相關訪問接口時,是不知道它是否被禁止讀取數(shù)據(jù)的。

HealthKit的數(shù)據(jù)不會保存在iCloud中,也不會在多設備間同步。這些數(shù)據(jù)只會保存在用戶的本地設備中。為了安全考慮,當設備沒有解鎖時,HealthKit存儲的數(shù)據(jù)是加密的。

另外,你的應用如果主要不是提供健康或健身服務的話,那就不能調(diào)用HealthKit的API。如果你的應用提供健康和健身服務,就必須要在App Store相關應用簡介和應用界面上明確的表明。

使用HealthKit特別注意

  1. 你的應用不應該將HealthKit收集的數(shù)據(jù)用于廣告或類似的服務。注意,在使用HealthKit框架應用中可以插播廣告,但是你不能使用HealthKit中的數(shù)據(jù)來服務廣告。

  2. 在沒有用戶的明確允許下,你不能向第三方展示任何HealthKit收集的數(shù)據(jù)。即使用戶允許,你也只能向提供健康或健身服務的第三方展示這些數(shù)據(jù)。

  3. 你不能將HealthKit收集的數(shù)據(jù)出售給廣告平臺、數(shù)據(jù)代理人或者信息經(jīng)銷商。

  4. 如果用戶允許,你可以將HealthKit數(shù)據(jù)共享給第三方用于醫(yī)學研究。注意是用戶允許

  5. 你必須明確說明,你和你的應用會怎樣使用用戶的HealthKit數(shù)據(jù)。

應用中使用了HealthKit 上 App Store 特別注意

  1. 一定要添加隱私政策網(wǎng)址鏈接,并注明健康數(shù)據(jù)使用的隱私相關條例。例如:

    • 在App里您設置身高、體重時,根據(jù)您之前是否允許授權權限,XXX將依據(jù)您給的權限是否把信息寫入蘋果健康應用。
    • 在App里同步計步、睡眠、心率數(shù)據(jù)時,根據(jù)您之前是否允許授權權限,XXX將依據(jù)您給的權限是否把信息寫入蘋果健康應用。
  2. 應用介紹中一定要注明:此版本支持你使用Apple健康應用程序

HealthKit設計目標

HealthKit是用來在應用間以一種有意義的方式共享數(shù)據(jù)。為了達到這點,框架限制只能使用預先定義好的數(shù)據(jù)類型和單位。這些限制保證了其他應用能理解這些數(shù)據(jù)是什么意思,以及怎樣使用。因此,開發(fā)者不能創(chuàng)建自定義數(shù)據(jù)類型和單位。而HealthKit盡量會提供一個完整的數(shù)據(jù)類型和單位。

HealthKit 存儲理念

框架大量使用了子類化,在相似的類間創(chuàng)建層級關系。通常這些類間都有一些細微但是重要的差別。還有不少和它相關的類,需要正確搭配,才能一起工作。存儲在HealthKit中的數(shù)據(jù)都是由對象和對象所屬類型組成,這個概念一定要刻入腦海,你才能理解整個存儲結構。所有對象都是基于HKObject,所有對象所屬的類型都是基于HKObjectType。下面簡單介紹下這兩個類:

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

  • HKObject 主要分為兩類:特征和樣本。特征對象代表一些基本不變的數(shù)據(jù)。例如:用戶的生日、血型和生理性別,膚色。你的應用不能寫入特征數(shù)據(jù)。用戶必須通過健康應用來輸入或者修改這些數(shù)據(jù)。

    • 樣本對象是某個特定時間斷的數(shù)據(jù)。所有的樣本對象都是HKSample的子類。它們都有下列屬性:
      • sampleType: 樣本類型。例如:一個睡眠分析樣本、一個身高樣本或者一個計步樣本。
      • startDate : 樣本的開始時間。
      • endDate : 樣本的結束時間。
  • HKObject 所有對象都是不可變的(除非修改了對象來源),創(chuàng)建對象時需設置對象的相關屬性。所有對象都有相同的屬性。如下所示:

    • 唯一的標識符UUID
    • 數(shù)據(jù)來源source 9.0版本后用sourceRevision
    • device生成這個對象數(shù)據(jù)的設備。
    • Metadata用來描述對象的額外信息,是NSDictionary類型,其中Key都為NSString類型,Value可以為NSString,NSNumber,NSDate類型。其中Key可以為系統(tǒng)預定義的也可以自定義。系統(tǒng)預定義的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;
  • 系統(tǒng)預定義類型的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

如何使用

  • 創(chuàng)建一個工程取名為: HealthKit
  • Xcode8.0 , iOS 10.0后需要在Info.plist文件中添加讀寫說明,是否感覺似曾相識,其實它和使用定位功能時,需要在Info.plist中添加說明一個道理。(Demo 中的說明只是告訴你相關描述對應的讀取或寫入操作而已,具體描述自己根據(jù)應用實際情況斟酌描述)如下圖所示:
屏幕快照 2016-09-24 12.22.54.png
  • TAGETS->Capabilities 打開->HealthKit如下圖所示:

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

這時工程將會自動將HealthKit.framework加入工程。

  • 創(chuàng)建一個管理我們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

方法調(diào)用

  • 首先我們需要把自己想要讀或寫的相關數(shù)據(jù)類型寫明。
#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. 判斷系統(tǒng)版本,低于8.0不可用。
  2. 判斷設備是否支持HealthKit。[HKHealthStore isHealthDataAvailable]
  3. 判斷用戶是否對這個類型的進行授權。authorizationStatusForType (基本不可變數(shù)據(jù)類型除外,例如:生日,性別,血型等)不對授權進行判斷,一般不會出問題在進行讀寫操作時也會有錯誤提示。但是對數(shù)據(jù)操作時系統(tǒng)判斷更耗時而且有時會出現(xiàn)莫名的錯誤。
  • 這里舉兩個例子說明下:
    • 對年齡進行讀操作。
    • 對身高進行寫操作。

年齡讀操作

-(void)readUsersAgeWithFinish:(ZHHealthKitIntegerValueBlock)finish
{
    NSInteger systemVersion = [[UIDevice currentDevice].systemVersion floatValue];
    if (systemVersion <8.0){//系統(tǒng)少于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){//系統(tǒng)少于8.0不可用
        return;
    }
    if (![HKHealthStore isHealthDataAvailable])//健康不可用直接返回
    {
        return;
    }
    HKQuantityType *weightType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass];
    if ([self.healthStore authorizationStatusForType:weightType] != HKAuthorizationStatusSharingAuthorized) {
        NSLog(@"未經(jīng)用戶允許訪問直接返回");
        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);
            }
        }];

}
  • 當然在進行其他樣本操作時,例如:記步,睡眠等等。如果有可能出現(xiàn)重復寫入,我們需要先進行判斷這段時間內(nèi)的數(shù)據(jù)是否已經(jīng)存入HealthKit。這里會用到查詢操作,具體可以參考我Demo中的HKHealthStore+ZHHKExtensions類。

Demo 下載地址

GitHub

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內(nèi)容