有关HealthKit的那些事

作者: Mars飘殇 | 来源:发表于2016-03-02 16:19 被阅读2672次

最近在做项目的时候,突然接到产品经理给的一个需求,要求在项目中统计用户每日步数,具体要求就是获取手机健康应用中统计的每日步数,然后以图形方式显示。

刚听到这个需求的时候就想到了苹果在iOS8系统推出之时顺带出的HealthKit框架,不过对于其API倒是非常的陌生。于是就开始在网上查找资料,百度,谷歌一番之后,发现也未能找到一个资料能够很好地引导新手使用该框架(可能是我没找到好的-_-!),经过几天的个人摸索,也算是有点心得体会,在这里就将自己对该框架相关的使用做个梳理,也希望能够为接下来即将接触和使用该框架的童鞋提供一点小小的帮助。如有什么疑问或者不对的地方欢迎提出。以下内容以获取步数为例,其他数据获取可以此类推。

一、项目中关联HealthKit框架

HealthKit关联路径

首先填写好你项目的Bundle Identifier并且选好Team(这两个东西最好事先设置好,以免之后又得重新关联),然后在项目物理文件结构中点选对应的项目,在TARGETS中选择你自身的项目,再在右侧选择Capabilities选项


HealthKit

从中找到HealthKit这项,点击右侧的开关开启,当出现中间红框所示的内容,表示项目与HealthKit框架关联成功了

成功关联HealthKit

你会在项目中看到多了HealthKit.framework和.entitlements结尾的这两个文件,OK一切顺利,接下来就可以Code了。

二、HealthKit所支持的系统和设备

因为HealthKit框架是在iOS8系统出来之时一同推出的,所以该框架目前只支持iOS8及以上系统,目前支持的设备有iPhone、iWatch,要记得iPad是不支持的哦,如果你的代码同时支持iPhone和iPad设备,那么记得判断下设备还有系统版本号,以免出现不必要的奔溃现象。在项目中导入<HealthKit/HealthKit.h>后,你也可以使用以下代码判断该设备的系统能否使用健康数据:

[HKHealthStore isHealthDataAvailable]

三、应用授权

要想获取健康数据中的步数,则需要通过用户许可才行。具体可以使用以下代码进行授权:

HKHealthStore *healthStore = [[HKHealthStore alloc] init];
NSSet *readObjectTypes = [NSSet setWithObjects:[HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount], nil];
[healthStore requestAuthorizationToShareTypes:nil readTypes:readObjectTypes completion:^(BOOL success, NSError *error) {
  //进行一些操作
}];

这里调用了requestAuthorizationToShareTypes: readTypes: completion:方法,用于对应用授权需要获取和分享的健康数据:

1、第一个参数传入一个NSSet类型数据,用于告知用户,我的app可能会在你的健康数据库中修改这些选项数据(显然目前我们不需要,传nil)
2、第二个参数也是传入NSSet类型数据,告知用户,我的app可能会从你的数据库中读取以下几项数据
3、第三个是授权许可回调,这里的BOOL值success不能用于区分用户是否允许应用向数据库存取数据,这一点评论区有人提到,我也对此进行了测试,发现确实即使用户不允许,该值也为YES

四、获取健康步数

授权完成之后,我们接下来就可以调用API来获取数据库数据了。

HKSampleType *sampleType = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];
NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:nil endDate:nil options:HKQueryOptionStrictStartDate];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:YES];
HKSampleQuery *sampleQuery = [[HKSampleQuery alloc] initWithSampleType:sampleType predicate:predicate limit:HKObjectQueryNoLimit sortDescriptors:@[sortDescriptor] resultsHandler:^(HKSampleQuery *query, NSArray *results, NSError *error) {
  if(!error && results) {
    for(HKQuantitySample *samples in results) {
      NSLog(@"%@ 至 %@ : %@", samples.startDate, samples.endDate, samples.quantity);
    }
  } else {
    //error
  }
}];
[healthStore executeQuery:sampleQuery];

这段代码主要做了以下几件事情:

1、第一段通过传入一个枚举值HKQuantityTypeIdentifierStepCount来创建一个样品类的实例,用于告知,我接下来要获取的数据是步数>2、第二段代码通过创建一个NSPredicate类的实例,用于获取在某个时间段的数据,这里startDate和endDate传入nil,表示获取全部数据,第三个参数传入一个Option,里面有三个值,这个参数我试验了下不同的值代入,发现返回的结果都是一样的,要是有谁知道这个值是做什么用的麻烦告知我一声~
3、第三段代码创建了一个NSSortDescriptor类实例,用于对查询的结果排序
4、第四段代码通过调用HKSampleQuery类的实例方法获取所需数据
5、最后一行代码用于执行数据查询操作

通过这段代码获取的数据,打印出来会发现,它获取的是比较详尽的数据,精确到每一小段时间从开始时间到结束时间内所获取的步数。

五、数据采集

有时候需求并不需要了解这么详尽的数据,只希望获取每小时、每天或者每月的步数,那么我们就需要用到另一个新类HKStatisticsCollectionQuery进行数据的分段采集

HKQuantityType *quantityType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];
NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
dateComponents.day = 1;
HKStatisticsCollectionQuery *collectionQuery = [[HKStatisticsCollectionQuery alloc] initWithQuantityType:quantityType quantitySamplePredicate:nil options: HKStatisticsOptionCumulativeSum | HKStatisticsOptionSeparateBySource anchorDate:[NSDate dateWithTimeIntervalSince1970:0] intervalComponents:dateComponents];
collectionQuery.initialResultsHandler = ^(HKStatisticsCollectionQuery *query, HKStatisticsCollection * __nullable result, NSError * __nullable error) {
  for (HKStatistics *statistic in result.statistics) {
    NSLog(@"\n%@ 至 %@", statistic.startDate, statistic.endDate);
    for (HKSource *source in statistic.sources) {
      if ([source.name isEqualToString:[UIDevice currentDevice].name]) {
        NSLog(@"%@ -- %f",source, [[statistic sumQuantityForSource:source] doubleValueForUnit:[HKUnit countUnit]]);
      }
    }
  }
};
[healthStore executeQuery:collectionQuery];

1、第一段代码所做的和之前的一样,定义需要获取的数据为步数
2、第二段代码创建一个NSDateComponents类实例,设置我要获取的步数时间间隔,这里设置为按天统计,这里也可以设置按小时或者按月统计
3、第三段代码创建查询统计对象collectionQuery,通过传入四个参数进行初始化:

1、第一个参数同上面一样,设置需要查询的类型
2、第二个参数传入一个NSPredicate实例,目前这里传nil
3、第三个参数是关键,传入一个Option可选值,告诉查询统计对象我需要获取的是啥,这里传入HKStatisticsOptionCumulativeSum | HKStatisticsOptionSeparateBySource值,获取时间段的步数和以及将数据根据不同的数据来源进行分段
4、第四个参数传入一个锚点,类似于数组的索引值,查询将会从改锚点开始查询,这里可以根据不同的锚点值,获取日/周/月/年数据

4、第四段代码是将collectionQuery对象的block属性initialResultsHandler进行赋值,该block会在数据查询成功之后进行回调,从中可以获得我们想要的数据
5、最后一行执行该查询统计操作执行这段代码,通过打印的日志可以看到当前设备中存储的按日间隔存储的步行数总和了。

返回的数据中HKSource对象中的name可用于区分健康数据来源,一般只获取设备中的步数,过滤其他第三方数据来源,目前微信、QQ所用的记步就是区分了不同的数据来源,防止作弊!!!

最后附上一个仿健康应用步数的Demo:
gitHub地址:https://github.com/MarsCWD/HealthKitDemo
参考链接:
http://vit0.com/blog/2014/10/30/ios-8-healthkit-jie-shao/
https://segmentfault.com/a/1190000003779081

相关文章

网友评论

  • 1ee8ad869c7e:楼主,有个问题请教一下 ,怎么获取运动时长呢
    1ee8ad869c7e:@Mars飘殇 3Q
    Mars飘殇:@janeywang 步数中应该看不出运动时长
  • zhouwude:请教你一个问题,微信和qq在健康里面关掉数据共享还是能拿到数据的,我在自己的app中就不行一直工地找到原因
    zhouwude:今天又侧试了一下,发现还是 读到了。
    zhouwude:@Mars飘殇 看了一下,关掉了还真能同步,换个手机试试看
    Mars飘殇:@zhouwude 你微信和QQ拿到的步数是缓存的吧?你在健康中关掉微信和QQ的步数共享,然后到第二天晚上去微信QQ看下有没数据
  • a12530ae42f3:问个问题:你文章中提到可以通过success来区分用户是否允许应用向数据库存取数据,但是我在进行用户不允许授权时,没有进行用户不允许的操作(我是在用户不允许时,输出一段话,但是在控制台上没有见到),什么原因?谢谢了
    a12530ae42f3:@Mars飘殇 根据官网文档上说的是To help prevent possible leaks of sensitive health information, your app cannot determine whether a user has granted permission to read data. If you are not given permission, it simply appears as if there is no data of the requested type in the HealthKit store. 那么我怎么知道用户点击了不允许按钮呢
    a12530ae42f3:@Mars飘殇 是的
    Mars飘殇:@望月GYQ 你是说在应用向健康授权获取数据的时候点了不允许是么?
  • 心中的信念:你公司app叫啥名呀参考
    心中的信念:@Mars飘殇 好的 :+1:
    Mars飘殇:@心中的信念 我目前做的项目是企业级应用,并未上架App Store :smile: ,你可以看下我在最后留的GitHub链接地址,去下一个Demo看看
  • 叶舞清风:我也要去面试这个有关的
    Mars飘殇:@叶舞清风 祝你早日找到:smile:
    叶舞清风:@Mars飘殇 嗯,辞职了,正在找
    Mars飘殇:@叶舞清风 面试?😨
  • 狗娃_: :heart_eyes: 猴塞雷。
    楼主我想请问一下,我通过这个demo获取我手机里的步数后,发现与健康中心里面的不一致(大概每天的步数都是差那么十几二十步),我的数据来源只有我的设备,没有其他来源。求解答! :pray:
    Mars飘殇:@阿牛哥_ 哈 我刚试了下确实有几个数据不对
    狗娃_:@Mars飘殇 点击“显示所有数据”进入后的界面里,每天的步数与健康中心不一致。:worried:
    Mars飘殇:@阿牛哥_ 你所说的每天的步数是指今日总步数吗?
  • d169c4184335:厉害
    Mars飘殇:@iwuqing 😁
  • fa4bf67720f7:牛逼🐂🐃
    Mars飘殇:@默认为零 :yum:

本文标题:有关HealthKit的那些事

本文链接:https://www.haomeiwen.com/subject/ntunkttx.html