HealthKit 那些事儿 - (步数算,步行+跑步距离)

2014年6月2日召开的年度开发者大会上,苹果发布了一款新的移动应用平台,可以收集和分析用户的健康数据,这是苹果计划为其计算和移动软件推出的一系列新功能的一部分,该移动应用平台被命名为“Healthkit ”。(iOS 8 开始推出)

Health Kit是一个管理用户体征参数的数据库,第三方应用可以向用户申请权限使用其中的数据或是向其中写入数据。

获取授权

HealthKit 采集的数据可能涉及用户的敏感数据,所以我们需要在获得授权。依然是在Target栏中,打开Capabilities菜单,将HealthKit这一部分的开关设为ON的状态,如屏幕截图中显示那样:

开启 healthKit 功能
开启 healthKit 功能

打开该功能后,在左侧的导航栏中会多出两个文件,如绿色箭头所示。

获取许可

导入HealthKit框架

我们使用HealthKit就需要导入HealthKit。导入HealthKit框架只需要下面一行代码即可:

#import <HealthKit/HealthKit.h>

设备检测

目前HealthKit仅仅可以在iPhone设备上使用,不能在iPad或者iPod中使用,所以在接入HealthKit代码之前最好检验下可用性。

if ([HKHealthStore isHealthDataAvailable]) {

}

请求授权

APP在使用HealthKit时,我们需要向用户获得读写数据的许可。接下来介绍APP如何获取用户许可。用户可以对不同来源的数据分别授权,权限分为读取与读写权限(苹果将读写权限称为share)。

// 初始化实例对象 用于 保存 HealthKit 数据
// 注意:HKHealthStore 在应用中应该只保存一个对象,因为每次创建新的对象,实际上相当于是同一个对象,可以理解为它们都会链接到同一个数据库。

 self.healthStore = [[HKHealthStore alloc] init];
 
 //步数 type
 HKObjectType *stepCount = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];

// 跑步、走路的距离type
HKObjectType *runDistance = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning];

// 添加到集合中
NSSet *readObjectTypes = [NSSet setWithObjects:stepCount,runDistance, nil];

#pragma mark 应用授权
    
[self.healthStore requestAuthorizationToShareTypes:nil readTypes:readObjectTypes completion:^(BOOL success, NSError *error) {
   
    //进行一些操作
    if (success)
    {
        NSLog(@"获取步数权限成功");
        
        //获取步数后我们调用获取步数的方法
        [self readStepCount];
    }
    else{
        NSLog(@"获取步数权限失败");
    }
    
    
}];

完成上述操作,真机测试会弹出是否允许访问健康数据的界面,如下图:

访问健康数据
访问健康数据

HKObjectType 定义HealthKit可以处理的所有类型的数据 (30种)有两个子类:HKCharacteristicType 和 HKSampleType

HKObjectType 层级结构图
HKObjectType 层级结构图

HKCharacteristicType 表示用户不会变化的数据,比如:生日、血型

HKSampleType 表示用户会变化的数据,比如:身高、体重、步数、距离等
HKSampleType 也有两个子类: HKQuantityType 和 HKCategoryType 表示 睡眠时间(sleep hours)等

HKObjectType 对象中主要有两个属性:

  • identifier 表示不同的数据类型
  • type name

我们可以根据需要创建不同类型的 HKObjectType:

  @interface HKobjectType : NSObject
  + (HKQuantityType *)quantityTypeForIdentifier:(NSString *)identifier;
  + (HKCategoryType *)categoryTypeForIdentifier:(NSString *)identifier;
  + (HKCharacteristicType *)characteristicTypeForIdentifier:(NSString *)identifier;
 @end

HKObject

所有存储在 HealthKit 中的数据都是 HKObject 的子类。HKObject 的类结构和 HKObjectType 的类结构很相似。


HKObject 层级关系图
HKObject 层级关系图

HKQuantitySample

是目前 HealthKit 中使用最广泛的一个 HKObject。它主要有两个属性:

 @interface HKQuantitySample
  @property (readonly) HKQuantityType *quantityType;  // 表示这个数量是什么类型的
  @property (readonly) HKQuantity *quantity; // 数量的值
 @end

HKCategorySample

它和 HKQuantitySample 类似

@interface HKCategorySample
    @property (readonly) HKCategoryType *categoryType;
    @property (readonly) NSInteger value;
@end

数据读取方法(这里以读取跑步和走路距离为例), 在上面授权成功中回调。

- (void)readStepCount{

// HKSampleType 会依据子类来确定这个类型的最终值 
    
// 步行或是跑步的距离 type
HKSampleType *sampleTypeForDistance = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning];
    
// 创建一个NSPredicate类的实例,用于获取在某个时间段的数据,这里startDate和endDate传入nil,表示获取全部数据,第三个参数传入一个Option,里面有三个值,保证在开始和结束的时间段,我是这样理解的,如果有错误请老师指正。
  • HKQueryOptionNone = 0,

  • HKQueryOptionStrictStartDate = 1 << 0,

  • HKQueryOptionStrictEndDate = 1 << 1,

    /**
    @enum HKQueryOptions
    @abstract Time interval options are used to describe how an HKSample's time period overlaps with a given time period.

    @constant HKQueryOptionNone The sample's time period must overlap with the predicate's time period.
    @constant HKQueryOptionStrictStartDate The sample's start date must fall in the time period (>= startDate, < endDate)
    @constant HKQueryOptionStrictEndDate The sample's end date must fall in the time period (>= startDate, < endDate)

    */

        NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:nil endDate:nil options:HKQueryOptionStrictStartDate];
        
        //NSSortDescriptors用来告诉healthStore怎么样将结果排序。
        NSSortDescriptor *start = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:NO];
        NSSortDescriptor *end = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierEndDate ascending:NO];
        
        
pragma mark -- 步行、跑步的距离 (详尽数据采集 可用于详细信息列表)
        
        HKSampleQuery *runDistanceSample = [[HKSampleQuery alloc] initWithSampleType:sampleTypeForDistance predicate:predicate limit:HKObjectQueryNoLimit sortDescriptors:@[start,end] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) {
            
            /**
             *   results 包含
             *   数量的值(步数、距离...)、设备名、起止时间...
             */
    
            /** HKQuantitySample 样品、数量
            @interface HKQuantitySample 有两个属性
            @property (readonly) HKQuantityType *quantityType;  // 表示这个数量是什么类型的
            @property (readonly) HKQuantity *quantity; // 数量的值
            @end
            */
            
            
            
            if(!error && results) {
           
                    for (HKQuantitySample *resultAll in results) {
                        
                        // 数量类型
                        //NSLog(@"%@",resultAll.quantityType);
    
                        // 数量(这里指距离)
                        HKQuantity *quantity = resultAll.quantity;
    
          
    #pragma mark HKUnit 
                        
                        //定义一个比较复杂的单位,
                        //HKUnit *meters = [HKUnit meterUnit];
                        //HKQuantity *grams = [HKQuantity quantityWithUnit:meters doubleValue:20];
                        
                        // HKQuantity 转成 double 类型
                        double Kmeters = [quantity doubleValueForUnit:[HKUnit unitFromString:@"mi"]] *1.609344;
                        
                        // 英里转换公里 打印公里 1 英里 约等于 1.609344 公里
                        //NSLog(@"  %.3f 公里", Kmeters);
                        
        
                        // 起止时间
                        NSString *runForStarData = [NSString stringWithFormat:@"%@",resultAll.startDate];
                        NSString *runForEndData = [NSString stringWithFormat:@"%@",resultAll.endDate];
    
                        // 数量转换成字符串
                        //NSString *stepStr = (NSString *)quantity;
                        // 转换完的公里数转成字符串
                        NSString *stepStr = [NSString stringWithFormat:@"%.3f",Kmeters];
                        
                        
                        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                            
                            //查询是在多线程中进行的,如果要对UI进行刷新,要回到主线程中
                            NSLog(@"%@ 时间到 %@ 时间 ,您走了 %@ 公里",runForStarData, runForEndData, stepStr);
                        }];
                        
                    }
         
            } else {
                
                //error
                NSLog(@"出错了!");
            }
             
            
        }];
    
            //进行查询
            [self.healthStore executeQuery:runDistanceSample];
    }
打印结果
打印结果

前人们的路线:
https://developer.apple.com/library/ios/documentation/HealthKit/Reference/HealthKit_Framework/index.html#//apple_ref/doc/uid/TP40014707
http://pandajohn.com/hello-world/
https://segmentfault.com/a/1190000003779081
http://vit0.com/blog/2014/10/30/ios-8-healthkit-jie-shao/
http://simcai.com/2015/12/27/iOS-HealthKit-%E8%AF%BB%E5%8F%96%E6%89%8B%E6%9C%BA%E6%AD%A5%E6%95%B0%E7%BB%9F%E8%AE%A1/
http://www.jianshu.com/p/ebe14a97525a

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

推荐阅读更多精彩内容