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

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

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

获取授权

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

开启 healthKit 功能

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

获取许可

导入HealthKit框架

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

#import 

设备检测

目前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(@"获取步数权限失败");
    }
    
    
}];

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

HealthKit 那些事儿 - (步数算,步行+跑步距离)_第1张图片
访问健康数据

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

HealthKit 那些事儿 - (步数算,步行+跑步距离)_第2张图片
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 层级关系图

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

你可能感兴趣的:(HealthKit 那些事儿 - (步数算,步行+跑步距离))