HealthKit之理论知识

简介:


1、#import <HealthKit/HealthKit.h>


2、创建HKHealthStore对象,通过它可以读取和存储用户的health数据。不过在读取和存储之前,首先要通过HKHealthStore执行方法+ (BOOL)isHealthDataAvailable;判断用户设备是否支持HealthKit。


3、我们读取和存储用户的health数据,就必须明确知道要操作的数据类型。在HealthKit里,数据类型有HKObjectType、HKSampleType、HKActivitySummaryType、HKCategoryType、HKCharacteristicType、HKCorrelationType、HKQuantityType和HKWorkoutType。它们的结构关系如图所示。

通过在HKObjectType.h类里定义的方法,

+ (nullable HKQuantityType *)quantityTypeForIdentifier:(NSString *)identifier;

+ (nullable HKCategoryType *)categoryTypeForIdentifier:(NSString *)identifier;

+ (nullable HKCharacteristicType *)characteristicTypeForIdentifier:(NSString *)identifier;

+ (nullable HKCorrelationType *)correlationTypeForIdentifier:(NSString *)identifier;

+ (HKWorkoutType *)workoutType;

+ (HKActivitySummaryType *)activitySummaryType NS_AVAILABLE_IOS(9_3);

可以去创建对应的数据类型。方法参数Identifier,是具体数据Id,在HKTypeIdentitytifiers.h类里定义。它们命名方式都是以所属类型名开始。比如:

    HKObjectType *type1 = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]; // 步数

    HKObjectType *type2 = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning]; // 步行+跑步距离

    HKObjectType *type3 = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierFlightsClimbed];     // 已爬楼层

    HKObjectType *tyep4 = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierActiveEnergyBurned]; // 活动能量

    HKObjectType *type5 = [HKObjectType activitySummaryType];// 健身记录


    HKObjectType *type6 = [HKObjectType correlationTypeForIdentifier:HKCorrelationTypeIdentifierFood];

    

    HKObjectType *type8 = [HKObjectType characteristicTypeForIdentifier:HKCharacteristicTypeIdentifierBiologicalSex]; // 性别

    HKObjectType *type9 = [HKObjectType characteristicTypeForIdentifier:HKCharacteristicTypeIdentifierBloodType];//血型

    HKObjectType *type10 = [HKObjectType characteristicTypeForIdentifier:HKCharacteristicTypeIdentifierDateOfBirth];//出生日期

    HKObjectType *type11 = [HKObjectType characteristicTypeForIdentifier:HKCharacteristicTypeIdentifierFitzpatrickSkinType];//日光反应型皮肤类型

    

    HKObjectType *type12 = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierSleepAnalysis];// 睡眠分析

    HKObjectType *type12 = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierAppleStandHour]; // 站立小时

    HKObjectType *type12 = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierCervicalMucusQuality]; // 宫颈粘液质量

    HKObjectType *type12 = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierOvulationTestResult]; // 排卵测试结果

    HKObjectType *type12 = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierMenstrualFlow]; // 月经

    HKObjectType *type12 = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierIntermenstrualBleeding];// 点滴出血

    HKObjectType *type12 = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierSexualActivity]; // 性行为


4、在读取和存储用户的health数据之前,我们需要请求授权,读取和存储哪些类型的Health数据。通过HKHealthStore对象执行- (void)requestAuthorizationToShareTypes:(nullable NSSet<HKSampleType *> *)typesToShare

                               readTypes:(nullable NSSet<HKObjectType *> *)typesToRead

                              completion:(void (^)(BOOL success, NSError * __nullable error))completion;参数shareTypes就是需要授权的存储数据类型,参数readTypes就是需要授权的读取数据类型,completion就是授权完成回调。授权过程是在子线程异步执行。代码参考:

HKObjectType *type1 = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]; // 步数

    HKObjectType *type2 = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning]; // 步行+跑步距离

    HKObjectType *type3 = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierFlightsClimbed];     // 已爬楼层

    HKObjectType *tyep4 = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierActiveEnergyBurned]; // 活动能量

    NSSet *rset = [NSSet setWithObjects:type1, type2, type3, tyep4, nil]; // 读集合

    

    

    HKSampleType *wType1 = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];

    HKCategoryType *wType2 = [HKCategoryType categoryTypeForIdentifier:HKCategoryTypeIdentifierSleepAnalysis];

    NSSet *wset = [NSSet setWithObjects:wType1, wType2, nil]; // 写集合

    

    __weak typeof (&*self) weakSelf = self;

    [_healthStore requestAuthorizationToShareTypes:wset readTypes:rset completion:^(BOOL success, NSError * _Nullable error) {

        if (success)

        {

            // 去读取和存储用户的health数据

        } else

        {

            NSLog(@"healthkit不允许读写");

        }

    }];


5、读取用户health数据,HKHealthStore提供了

- (nullable NSDate *)dateOfBirthWithError:(NSError **)error;

- (nullable HKBiologicalSexObject *)biologicalSexWithError:(NSError **)error;

- (nullable HKBloodTypeObject *)bloodTypeWithError:(NSError **)error;

- (nullable HKFitzpatrickSkinTypeObject *)fitzpatrickSkinTypeWithError:(NSError **)error;

可以直接读用户的出生日期、性别、血型和日光反应型皮肤类型。

而需要读取更多的数据,就得创建查询条件去查询数据,查询就得用到HKQuery,它的子类有:

HKSampleQuery(HKSampleType类型数据查询,简称样本查询),HKActivitySummaryQuery(HKActivitySummaryType数据类型查询,即健身记录查询),

HKCorrelationQuery(HKCorrelationType数据类型查询),

HKAnchoredObjectQuery(锚点查询,即分页查询),

HKObserverQuery(观察查询,即查询的数据发生变化时能监听到),

HKStatisticsQuery(统计查询,比如统计今天步数),

HKStatisticsCollectionQuery(从某一时间开始,以一定的时间间隔按条件查询,比如统计今天活动记录中每一小时的步数,即6点多少步,8店多少步,15点多少步),

HKSourceQuery(数据来源查询,比如查询来源小米手环的所有数据)。

代码参考:

// 查询今天步数

NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];

    NSDateComponents *dateCom = [calendar components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit fromDate:[NSDate date]];

    

    NSDate *endDate = [calendar dateFromComponents:dateCom];

    

    [dateCom setHour:0];

    [dateCom setMinute:0];

    [dateCom setSecond:0];

    

    NSDate *startDate = [calendar dateFromComponents:dateCom];

    NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:startDate endDate:endDate options:HKQueryOptionStrictStartDate];


HKQuantityType *sampleType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];

    

    //NSSortDescriptors用来告诉healthStore怎么样将结果排序。

    NSSortDescriptor *start = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:NO];

    NSSortDescriptor *end   = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierEndDate ascending:NO];


__weak typeof (&*_healthStore)weakHealthStore = _healthStore;

    

    HKSampleQuery *q1 = [[HKSampleQuery alloc] initWithSampleType:sampleType predicate:predicate limit:HKObjectQueryNoLimit sortDescriptors:@[start,end] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) {

        double sum = 0;

        double sumTime = 0;

        NSLog(@"步数结果=%@", results);

        for (HKQuantitySample *res in results)

        {

            

            sum += [res.quantity doubleValueForUnit:[HKUnit countUnit]];

            

            NSTimeZone *zone = [NSTimeZone systemTimeZone];

            NSInteger interval = [zone secondsFromGMTForDate:res.endDate];

            

            NSDate *startDate = [res.startDate dateByAddingTimeInterval:interval];

            NSDate *endDate   = [res.endDate dateByAddingTimeInterval:interval];


            sumTime += [endDate timeIntervalSinceDate:startDate];

        }

        int h = sumTime / 3600;

        int m = ((long)sumTime % 3600)/60;

        NSLog(@"运动时长:%@小时%@分", @(h), @(m));

        NSLog(@"运动步数:%@步", @(sum));

        if(error) NSLog(@"1error==%@", error);

        [weakHealthStore stopQuery:query];

        [[NSOperationQueue mainQueue] addOperationWithBlock:^{

                //查询是在多线程中进行的,如果要对UI进行刷新,要回到主线程中

            }];;

    }];

//执行查询

    [_healthStore executeQuery:q1];

查询完成时,有一处还需要我们注意,就是单位转换。单位类HKUnit,哪怎么知道查询得到的数据是什么单位呢,在HKTypeIdentifiers.h类里定义数据Id后面都有标明,

比如:

HK_EXTERN NSString * const HKQuantityTypeIdentifierStepCount NS_AVAILABLE_IOS(8_0);                 // Scalar(Count),               Cumulative

步数的单位是Scalar(Count),我们就到HKUnit.h类搜索Scalar,找到HKUnit扩展@interface HKUnit (Scalar);而(Count)表明需要执行此扩展的+ (instancetype)countUnit; 得到所需的单位类。

当然我也可以为数据类自定义单位类。

通过HKHealthStore对象的方法来做到

- (void)preferredUnitsForQuantityTypes:(NSSet<HKQuantityType *> *)quantityTypes completion:(void(^)(NSDictionary<HKQuantityType*, HKUnit *> *preferredUnits, NSError * __nullable error))completion NS_AVAILABLE_IOS(8_2);


6、存储和删除health数据,通过HKHealthStore对象的方法来做到

存储方法

- (void)saveObject:(HKObject *)object withCompletion:(void(^)(BOOL success, NSError * __nullable error))completion;

- (void)saveObjects:(NSArray<HKObject *> *)objects withCompletion:(void(^)(BOOL success, NSError * __nullable error))completion;


删除方法

- (void)deleteObject:(HKObject *)object withCompletion:(void(^)(BOOL success, NSError * __nullable error))completion;

- (void)deleteObjects:(NSArray<HKObject *> *)objects withCompletion:(void(^)(BOOL success, NSError * __nullable error))completion NS_AVAILABLE_IOS(9_0);

- (void)deleteObjectsOfType:(HKObjectType *)objectType predicate:(NSPredicate *)predicate withCompletion:(void(^)(BOOL success, NSUInteger deletedObjectCount, NSError * __nullable error))completion NS_AVAILABLE_IOS(9_0);


这里主要介绍下参数object,是HKObject数据对象,其包括UUID、来源信息HKSourceHKSourceRevision、设备信息HKDevice和元数据HKMetadata。

HKSource,包括来源名称和唯一标识符,系统8.0以下使用。

HKSourceRevision,包括来源名称、唯一标识符和版本号,系统8.0以上使用。

HKDevice,包括设备的名称、制造商、型号、硬件版本和软件版本等。

HKMetadata,可以设置设备序列号、身体温度传感器的位置、心率传感器的位置、数字签名、是否是室内室外锻炼等。

HKObject有四个子类HKSample、HKWorkout、HKCorrelation和HKCategorySample。


代码参考:

// 睡眠分析

    HKCategoryType *categoryType = [HKCategoryType categoryTypeForIdentifier:HKCategoryTypeIdentifierSleepAnalysis];

    HKDevice *device = [[HKDevice alloc] initWithName:@"文能设备" manufacturer:@"中国制造商" model:@"智能机" hardwareVersion:@"1.0.0" firmwareVersion:@"1.0.0" softwareVersion:@"1.0.0" localIdentifier:@"lizaochengwen" UDIDeviceIdentifier:@"wennengshebei"];

    HKCategorySample *testObject = [HKCategorySample categorySampleWithType:categoryType value:0.25 startDate:[NSDate dateWithTimeIntervalSinceNow:-(24 * 3600)] endDate:[NSDate date] device:device metadata:nil];

    [_healthStore saveObject:testObject withCompletion:^(BOOL success, NSError * _Nullable error) {

        if (success) {

            NSLog(@"文能设备,收集的睡眠记录保存成功");

        } else

        {

             NSLog(@"文能设备,收集的睡眠记录保存失败 %@", error);

        }

    }];

    

    NSMutableArray *list= [[NSMutableArray alloc] init];

    for (float i = 1; i < 100; i++) {

        HKCategorySample *testObject = [HKCategorySample categorySampleWithType:categoryType value:i/100.0 startDate:[NSDate dateWithTimeIntervalSinceNow:-(24 * 3600/i)] endDate:[NSDate date] device:device metadata:nil];

        [list addObject:testObject];

    }

    [_healthStore saveObjects:list withCompletion:^(BOOL success, NSError * _Nullable error) {

        if (success) {

            NSLog(@"文能设备,收集的睡眠记录保存成功");

        } else

        {

            NSLog(@"文能设备,收集的睡眠记录保存失败 %@", error);

        }

    }];

    

    NSSet *dSet= [[NSSet alloc] initWithObjects:@"文能设备", nil];

    NSPredicate *catePredicate = [HKQuery predicateForObjectsWithDeviceProperty:HKDevicePropertyKeyName allowedValues:dSet];

    [_healthStore deleteObjectsOfType:categoryType predicate:catePredicate withCompletion:^(BOOL success, NSUInteger deletedObjectCount, NSError * _Nullable error) {

        if (success) {

            NSLog(@"文能设备,收集的睡眠记录删除成功 %@", @(deletedObjectCount));

        } else

        {

            NSLog(@"文能设备,收集的睡眠记录删除失败 %@", error);

        }

    }];

目录
相关文章
|
7月前
|
存储 JavaScript 前端开发
“纯血鸿蒙”要来了,赶紧入手学习吧
1月18日,华为宣布HarmonyOSNEXT鸿蒙星河版面向开发者开放申请,这一最新版本的鸿蒙系统也被喻为“纯血鸿蒙”。赶紧入手学习吧
393 1
|
4月前
|
JavaScript 前端开发 数据挖掘
【幕后揭秘】Tornado框架何以称霸?带你一探究竟,解锁Web开发新潮流的秘密武器!
【8月更文挑战第31天】Tornado 是一款用 Python 编写的高性能非阻塞网络框架,以其处理大量并发连接的能力著称,适用于实时 Web 应用。它最初由 FriendFeed 开发并开源,现已广泛应用于多种场景。Tornado 的核心优势在于异步 I/O 处理机制,可在单线程内处理数万并发连接,非常适合实时应用如在线聊天、游戏等。本文将详细介绍 Tornado 的核心特点,并通过具体示例代码展示其在实际项目中的应用,帮助读者理解 Tornado 如何引领 Web 开发新潮流。
38 0
|
存储 算法 Java
【C++数据结构】启航,打开新世界的大门!
【C++数据结构】启航,打开新世界的大门!
|
7月前
|
前端开发 JavaScript 开发工具
前端知识笔记(三十)———前端需要掌握的技术有哪些方面
前端知识笔记(三十)———前端需要掌握的技术有哪些方面
101 1
|
存储 编解码 API
游戏编程之四 diectxdarw基础篇
游戏编程之四 diectxdarw基础篇
69 0
|
编译器 程序员 C语言
游戏编程之二 windows编程基础
游戏编程之二 windows编程基础
82 0
|
机器学习/深度学习 人工智能 算法
【如何入门编程】编程升级通关绝招
【如何入门编程】编程升级通关绝招
58 0
|
Web App开发 前端开发 图形学
Unity实战问题-WebGL问题集锦-上篇
众所周知,人生是一个漫长的流程,不断克服困难,不断反思前进的过程。在这个过程中会产生很多对于人生的质疑和思考,于是我决定将自己的思考,经验和故事全部分享出来,以此寻找共鸣!!!
448 1
|
设计模式 XML 人工智能
太牛了!Android开发高级工程师实战手写框架
导语 又到了金九银十的面试季,自己也不得不参与到这场战役中来,其实是从去年底就开始看,Android的好机会确实不太多,但也还好,3年+的android开发经历还是有一些面试机会的,不过确实不像几年前门槛那么低了,总的体会就是小的创业公司比较注重你的项目经历是否和自己的贴合,直接能过来独当一面。 大厂除了看中项目经历外,还比较注重你知识面的广度,是广度、深度和解决方案等多方面的考察,平时够工作要好好积累临时刷题只聊点皮毛估计是过不了关的。下面就总结一些大厂面试遇到必定会问的知识点,我把网络上讲解的最好的视频给大家整理出来了,各种风格的都有。
太牛了!Android开发高级工程师实战手写框架