如何使用Apple HealthKit获得每日睡眠时间?

我正在做一个应用程序,每天读取步骤,并从苹果HealthKit睡眠数据。

对于步骤来说 ,这很容易,因为它是HKQuantityType ,所以我可以在其上应用HKStatisticsOptionCumulativeSum选项。 将开始date,结束date和date时间间隔放在中,然后就可以了。

 - (void)readDailyStepsSince:(NSDate *)date completion:(void (^)(NSArray *results, NSError *error))completion { NSDate *today = [NSDate date]; NSCalendar *calendar = [NSCalendar currentCalendar]; NSDateComponents *comps = [calendar components:NSCalendarUnitDay|NSCalendarUnitMonth|NSCalendarUnitYear fromDate:date]; comps.hour = 0; comps.minute = 0; comps.second = 0; NSDate *midnightOfStartDate = [calendar dateFromComponents:comps]; NSDate *anchorDate = midnightOfStartDate; HKQuantityType *stepType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]; HKStatisticsOptions sumOptions = HKStatisticsOptionCumulativeSum; NSPredicate *dateRangePred = [HKQuery predicateForSamplesWithStartDate:midnightOfStartDate endDate:today options:HKQueryOptionNone]; NSDateComponents *interval = [[NSDateComponents alloc] init]; interval.day = 1; HKStatisticsCollectionQuery *query = [[HKStatisticsCollectionQuery alloc] initWithQuantityType:stepType quantitySamplePredicate:dateRangePred options:sumOptions anchorDate:anchorDate intervalComponents:interval]; query.initialResultsHandler = ^(HKStatisticsCollectionQuery *query, HKStatisticsCollection *result, NSError *error) { NSMutableArray *output = [NSMutableArray array]; // we want "populated" statistics only, so we use result.statistics to iterate for (HKStatistics *sample in result.statistics) { double steps = [sample.sumQuantity doubleValueForUnit:[HKUnit countUnit]]; NSDictionary *dict = @{@"date": sample.startDate, @"steps": @(steps)}; //NSLog(@"[STEP] date:%@ steps:%.0f", s.startDate, steps); [output addObject:dict]; } dispatch_async(dispatch_get_main_queue(), ^{ if (completion != nil) { NSLog(@"[STEP] %@", output); completion(output, error); } }); }; [self.healthStore executeQuery:query]; } 

但是对于睡眠来说,这并不是那么简单。 有很多东西我坚持。

  • 首先,与步骤不同,sleep是HKCategoryType 。 所以我们不能使用HKStatisticsCollectionQuery进行求和,因为这个方法只接受HKQuantityType
  • 还有2种价值types的睡眠, HKCategoryValueSleepAnalysisInBedHKCategoryValueSleepAnalysisAsleep 。 我不确定哪个价值最适合睡眠时间。 我只是为了简单起见而使用HKCategoryValueSleepAnalysisAsleep
  • 睡眠数据出现在HKCategorySample对象的数组中。 每个都有开始date和结束date。 如何有效地合并这些数据,在一天之内修剪它,并从中获得每日睡眠时间(以分钟为单位)? 我在DateTool pod中find了这个DTTimePeriodCollection类,可以完成这个工作,但是我还没弄明白。

简单地说,如果有人知道如何使用Apple HealthKit获得每日睡眠时间,请告诉我!

我用这个:

 @import HealthKit; @implementation HKHealthStore (AAPLExtensions) - (void)hkQueryExecute:(void (^)(double, NSError *))completion { NSCalendar *calendar = [NSCalendar currentCalendar]; NSDate *now = [NSDate date]; NSDateComponents *components = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay fromDate:now]; NSDate *startDate = [calendar dateFromComponents:components]; NSDate *endDate = [calendar dateByAddingUnit:NSCalendarUnitDay value:1 toDate:startDate options:0]; HKSampleType *sampleType = [HKSampleType categoryTypeForIdentifier:HKCategoryTypeIdentifierSleepAnalysis]; NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:startDate endDate:endDate options:HKQueryOptionNone]; HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:sampleType predicate:predicate limit:0 sortDescriptors:nil resultsHandler:^(HKSampleQuery *query, NSArray *results, NSError *error) { if (!results) { NSLog(@"An error occured fetching the user's sleep duration. In your app, try to handle this gracefully. The error was: %@.", error); completion(0, error); abort(); } double minutesSleepAggr = 0; for (HKCategorySample *sample in results) { NSTimeInterval distanceBetweenDates = [sample.endDate timeIntervalSinceDate:sample.startDate]; double minutesInAnHour = 60; double minutesBetweenDates = distanceBetweenDates / minutesInAnHour; minutesSleepAggr += minutesBetweenDates; } completion(minutesSleepAggr, error); }]; [self executeQuery:query]; } 

然后在视图控制器中:

 - (void)updateUsersSleepLabel { [self.healthStore hkQueryExecute: ^(double minutes, NSError *error) { if (minutes == 0) { NSLog(@"Either an error occured fetching the user's sleep information or none has been stored yet."); dispatch_async(dispatch_get_main_queue(), ^{ self.sleepDurationValueLabel.text = NSLocalizedString(@"Not available", nil); }); } else { int hours = (int)minutes / 60; int minutesNew = (int)minutes - (hours*60); NSLog(@"hours slept: %ld:%ld", (long)hours, (long)minutesNew); dispatch_async(dispatch_get_main_queue(), ^{ self.sleepDurationValueLabel.text = [NSString stringWithFormat:@"%d:%d", hours, minutesNew] ; }); } }]; }