iOS利用HealthKit获取健康里的步数和睡眠时间

最近做一个健康的项目,需要获取运动步数,睡眠时间,于是研究了一下HealthKit,下面分享一下,下来几张图:
Demo下载地址:
https://github.com/TechAlleyBoy/HealthKitDemo
http://download.csdn.net/download/techalleyboy/9867771
这里写图片描述

这里写图片描述

这里写图片描述

一:准备工作
1:在开发者账号(https://developer.apple.com)中配置AppID时需要选中HealthKit。如下图
这里写图片描述

2:在targets的capabilities中打开HealthKit。如下图
这里写图片描述

3:infoPlist需要配置权限 NSHealthUpdateUsageDescription 如下图
这里写图片描述

    <key>NSHealthShareUsageDescription</key>
    <string>是否允许更新健康数据</string>
    <key>NSHealthUpdateUsageDescription</key>
    <string>是否允许分享健康数据</string>

二:创建一个健康的单例管理类HealthKitManager
1:.h文件,解释详见代码注释

/**
 * 健康单例
 */
+ (instancetype)sharedInstance;

/**
 * 检查是否支持获取健康数据
 */
- (void)authorizeHealthKit:(void(^)(BOOL success, NSError *error))compltion;

/**
 * 获取步数
 */
- (void)getStepCount:(void(^)(NSString *stepValue, NSError *error))completion;

/**
 * 获取睡眠
 */
- (void)getSleepCount:(void(^)(NSString *sleepValue, NSError *error))completion;

2:.m文件,解释详见代码注释
注意:
1):统计步数的时间是,今天00:00:00 - 今天23:59:59
2):统计睡眠的时间是,昨天12:00:00 - 今天12:00:00

//
//  HealthKitManager.m
//  BJTResearch
//
//  Created by yunlong on 2017/6/9.
//  Copyright © 2017年 yunlong. All rights reserved.
//

#import "HealthKitManager.h"
#import <HealthKit/HealthKit.h>
@interface HealthKitManager ()
//HKHealthStore类提供用于访问和存储用户健康数据的界面。
@property (nonatomic, strong) HKHealthStore *healthStore;
@end
@implementation HealthKitManager

#pragma mark - 健康单例
+ (instancetype)sharedInstance {
    static HealthKitManager *instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[HealthKitManager alloc] init];
    });
    return instance;
}


#pragma mark - 检查是否支持获取健康数据
- (void)authorizeHealthKit:(void(^)(BOOL success, NSError *error))compltion {
    if (![HKHealthStore isHealthDataAvailable]) {
        NSError *error = [NSError errorWithDomain: @"不支持健康数据" code: 2 userInfo: [NSDictionary dictionaryWithObject:@"HealthKit is not available in th is Device"                                                                      forKey:NSLocalizedDescriptionKey]];
        if (compltion != nil) {
            compltion(NO, error);
        }
        return;
    }else{
        if(self.healthStore == nil){
            self.healthStore = [[HKHealthStore alloc] init];
        }
        //组装需要读写的数据类型
        NSSet *writeDataTypes = [self dataTypesToWrite];
        NSSet *readDataTypes = [self dataTypesRead];
        //注册需要读写的数据类型,也可以在“健康”APP中重新修改
        [self.healthStore requestAuthorizationToShareTypes:writeDataTypes readTypes:readDataTypes completion:^(BOOL success, NSError *error) {

            if (compltion != nil) {
                NSLog(@"error->%@", error.localizedDescription);
                compltion (YES, error);
            }
        }];
    }
}

#pragma mark - 写权限
- (NSSet *)dataTypesToWrite{
    //步数
    HKQuantityType *stepCountType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];
    //身高
    HKQuantityType *heightType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeight];
    //体重
    HKQuantityType *weightType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass];
    //活动能量
    HKQuantityType *activeEnergyType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierActiveEnergyBurned];
    //体温
    HKQuantityType *temperatureType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyTemperature];
    //睡眠分析
    HKCategoryType *sleepAnalysisType = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierSleepAnalysis];
    return [NSSet setWithObjects:stepCountType,heightType, temperatureType, weightType,activeEnergyType,sleepAnalysisType,nil];
}

#pragma mark - 读权限
- (NSSet *)dataTypesRead{
    //身高
    HKQuantityType *heightType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeight];
    //体重
    HKQuantityType *weightType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass];
    //体温
    HKQuantityType *temperatureType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyTemperature];
    //出生日期
    HKCharacteristicType *birthdayType = [HKObjectType characteristicTypeForIdentifier:HKCharacteristicTypeIdentifierDateOfBirth];
    //性别
    HKCharacteristicType *sexType = [HKObjectType characteristicTypeForIdentifier:HKCharacteristicTypeIdentifierBiologicalSex];
    //步数
    HKQuantityType *stepCountType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];
    //步数+跑步距离
    HKQuantityType *distance = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierDistanceWalkingRunning];
    //活动能量
    HKQuantityType *activeEnergyType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierActiveEnergyBurned];
    //睡眠分析
    HKCategoryType *sleepAnalysisType = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierSleepAnalysis];

    return [NSSet setWithObjects:heightType, temperatureType,birthdayType,sexType,weightType,stepCountType, distance, activeEnergyType,sleepAnalysisType,nil];
}

#pragma mark - 获取步数
- (void)getStepCount:(void(^)(NSString *stepValue, NSError *error))completion{

    //要检索的数据类型。
    HKQuantityType *stepType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];

    //NSSortDescriptors用来告诉healthStore怎么样将结果排序。
    NSSortDescriptor *start = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:NO];
    NSSortDescriptor *end = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierEndDate ascending:NO];

    /*
     @param         sampleType      要检索的数据类型。
     @param         predicate       数据应该匹配的基准。
     @param         limit           返回的最大数据条数
     @param         sortDescriptors 数据的排序描述
     @param         resultsHandler  结束后返回结果
     */
    HKSampleQuery*query = [[HKSampleQuery alloc] initWithSampleType:stepType predicate:[HealthKitManager getStepPredicateForSample] limit:HKObjectQueryNoLimit sortDescriptors:@[start,end] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) {
        if(error){
            completion(0,error);
        }else{
            NSLog(@"resultCount = %ld result = %@",results.count,results);
            //把结果装换成字符串类型
            double totleSteps = 0;
            for(HKQuantitySample *quantitySample in results){
                HKQuantity *quantity = quantitySample.quantity;
                HKUnit *heightUnit = [HKUnit countUnit];
                double usersHeight = [quantity doubleValueForUnit:heightUnit];
                totleSteps += usersHeight;
            }
            NSLog(@"最新步数:%ld",(long)totleSteps);
            completion([NSString stringWithFormat:@"%ld",(long)totleSteps],error);
        }
    }];
    [self.healthStore executeQuery:query];
}

#pragma mark - 获取睡眠(昨天12点到今天12点)
- (void)getSleepCount:(void(^)(NSString *sleepValue, NSError *error))completion{

    //要检索的数据类型。
    HKSampleType *sleepType = [HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierSleepAnalysis];

    NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierEndDate ascending:false];


    HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:sleepType predicate:[HealthKitManager getSleepPredicateForSample] limit:HKObjectQueryNoLimit sortDescriptors:@[sortDescriptor] resultsHandler:^(HKSampleQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable results, NSError * _Nullable error) {
        if (error) {
            NSLog(@"=======%@", error.domain);
        }else{
            NSLog(@"resultCount = %ld result = %@",results.count,results);
            NSInteger totleSleep = 0;
            for (HKCategorySample *sample in results) {//0:卧床时间 1:睡眠时间  2:清醒状态
                NSLog(@"=======%@=======%ld",sample, sample.value);
                if (sample.value == 1) {
                    NSTimeInterval i = [sample.endDate timeIntervalSinceDate:sample.startDate];
                    totleSleep += i;
                }
            }
            NSLog(@"睡眠分析:%.2f",totleSleep/3600.0);
            completion([NSString stringWithFormat:@"%.2f",totleSleep/3600.0],error);
        }
    }];

    [self.healthStore executeQuery:query];
}


#pragma mark - 当天时间段
+ (NSPredicate *)getStepPredicateForSample {
    NSDate *now = [NSDate date];
    NSDateFormatter * formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"yyyyMMdd"];
    NSString *startFormatValue = [NSString stringWithFormat:@"%@000000",[formatter stringFromDate:now]];
    NSString *endFormatValue = [NSString stringWithFormat:@"%@235959",[formatter stringFromDate:now]];
    [formatter setDateFormat:@"yyyyMMddHHmmss"];
    NSDate * startDate = [formatter dateFromString:startFormatValue];
    NSDate * endDate = [formatter dateFromString:endFormatValue];
    NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:startDate endDate:endDate options:HKQueryOptionNone];
    return predicate;
}

#pragma mark - 昨天12点到今天12点
+ (NSPredicate *)getSleepPredicateForSample {
    NSDateFormatter * formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"yyyyMMdd"];
    //今天12点
    NSDate *now = [NSDate date];
    NSString *endFormatValue = [NSString stringWithFormat:@"%@120000",[formatter stringFromDate:now]];

    //昨天12点
    NSDate *lastDay = [NSDate dateWithTimeInterval:-24*60*60 sinceDate:now];//前一天
    NSString *startFormatValue = [NSString stringWithFormat:@"%@120000",[formatter stringFromDate:lastDay]];

    [formatter setDateFormat:@"yyyyMMddHHmmss"];
    NSDate * startDate = [formatter dateFromString:startFormatValue];
    NSDate * endDate = [formatter dateFromString:endFormatValue];
    NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:startDate endDate:endDate options:HKQueryOptionNone];
    return predicate;
}

@end

三:控制器UIViewController中调用HealthKitManager

#import "ViewController.h"
#import "HealthKitManager.h"
@interface ViewController ()
//步数
@property(nonatomic,strong) UILabel *stepLabel;

//睡眠
@property(nonatomic,strong) UILabel *sleepLabel;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.view.backgroundColor = [UIColor whiteColor];

    UIButton *stepBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    stepBtn.frame = CGRectMake(50, 100, 50, 40);
    [stepBtn setTitle:@"步数" forState:UIControlStateNormal];
    [stepBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    stepBtn.backgroundColor = [UIColor redColor];
    [self.view addSubview:stepBtn];
    [stepBtn addTarget:self action:@selector(stepBtnClick) forControlEvents:UIControlEventTouchUpInside];

    _stepLabel = [[UILabel alloc] initWithFrame:CGRectMake(110, 100, 200, 40)];
    _stepLabel.backgroundColor = [UIColor greenColor];
    _stepLabel.textAlignment = NSTextAlignmentCenter;
    _stepLabel.textColor = [UIColor blackColor];
    [self.view addSubview:_stepLabel];

    UIButton *sleepBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    sleepBtn.frame = CGRectMake(50, 150, 50, 40);
    [sleepBtn setTitle:@"睡眠" forState:UIControlStateNormal];
    [sleepBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    sleepBtn.backgroundColor = [UIColor redColor];
    [self.view addSubview:sleepBtn];
    [sleepBtn addTarget:self action:@selector(sleepBtnClick) forControlEvents:UIControlEventTouchUpInside];

    _sleepLabel = [[UILabel alloc] initWithFrame:CGRectMake(110, 150, 200, 40)];
    _sleepLabel.backgroundColor = [UIColor greenColor];
    _sleepLabel.textAlignment = NSTextAlignmentCenter;
    _sleepLabel.textColor = [UIColor blackColor];
    [self.view addSubview:_sleepLabel];
}

#pragma mark - 获取步数
- (void)stepBtnClick{
    [[HealthKitManager sharedInstance] authorizeHealthKit:^(BOOL success, NSError *error) {
        if (success) {
            [[HealthKitManager sharedInstance] getStepCount:^(NSString *stepValue, NSError *error) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    _stepLabel.text = [NSString stringWithFormat:@"步数:%@步", stepValue];
                });
            }];
        }else{
            NSLog(@"=======%@", error.domain);
        }
    }];
}

#pragma mark - 获取睡眠
- (void)sleepBtnClick{
    [[HealthKitManager sharedInstance] authorizeHealthKit:^(BOOL success, NSError *error) {
        if (success) {
            [[HealthKitManager sharedInstance] getSleepCount:^(NSString *sleepValue, NSError *error) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    _sleepLabel.text = [NSString stringWithFormat:@"睡眠:%@小时", sleepValue];
                });
            }];
        }
    }];
}

如果觉得我的文章对您有用,请顶一下。您的支持将鼓励我继续创作!

猜你喜欢

转载自blog.csdn.net/techalleyboy/article/details/72965387