简体   繁体   English

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

[英]How to get daily sleep duration using Apple HealthKit?

I'm doing an app that reads daily steps and sleep data from Apple HealthKit. 我正在做一个应用程序,它从Apple HealthKit读取日常步骤和睡眠数据。

For Steps , it's pretty easy because it is a HKQuantityType , so I can apply HKStatisticsOptionCumulativeSum option on it. 对于Steps ,这很容易,因为它是HKQuantityType ,因此我可以在其上应用HKStatisticsOptionCumulativeSum选项。 Put the start date, end date, and date interval in, and you got it. 输入开始日期,结束日期和日期间隔,就可以了。

- (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];
}

But for Sleep it's not so straight forward. 但是对于睡眠而言 ,并不是那么简单。 There are many things I stuck on. 我坚持了很多东西。

  • First, unlike steps, sleep is a HKCategoryType . 首先,与步骤不同,sleep是HKCategoryType So we cannot use HKStatisticsCollectionQuery to sum it because this method only accepts HKQuantityType . 因此,我们不能使用HKStatisticsCollectionQuery对其求和,因为此方法仅接受HKQuantityType
  • Also there are 2 value types of sleep, HKCategoryValueSleepAnalysisInBed and HKCategoryValueSleepAnalysisAsleep . 还有2种值的睡眠类型, HKCategoryValueSleepAnalysisInBedHKCategoryValueSleepAnalysisAsleep I'm not sure which value is best for just the sleep duration. 我不确定哪个值最适合睡眠时间。 I'll just use HKCategoryValueSleepAnalysisAsleep only for simplicity. 我仅出于简单起见使用HKCategoryValueSleepAnalysisAsleep
  • Sleep data comes in an array of HKCategorySample objects. 睡眠数据来自HKCategorySample对象数组。 Each with start date and end date. 每个都有开始日期和结束日期。 How do I effectively combine those data, trim it to within a day, and get the daily sleep duration (in minutes) out of it? 如何有效地合并这些数据,将其修剪到一天之内,并从中获取每天的睡眠时间(以分钟为单位)? I found this DTTimePeriodCollection class in DateTool pod that may do this job, but I haven't figure it out yet. 我在DateTool窗格中找到了这个DTTimePeriodCollection类,它可以完成此工作,但我还没有弄清楚。

Simply put, if anyone knows how to get daily sleep duration using Apple HealthKit, please tell me! 简而言之,如果有人知道如何使用Apple HealthKit获得每日睡眠时间,请告诉我!

I used this: 我用这个:

@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];
}

And then in view controller: 然后在视图控制器中:

- (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] ;
        });
    }


}];
}

Check how I have did this, its working for me to get collection of the sleep data 检查我是如何做到的,它对我有用以收集睡眠数据

func sleepTime() {
        let healthStore = HKHealthStore()
        // startDate and endDate are NSDate objects
        // first, we define the object type we want
        if let sleepType = HKObjectType.categoryType(forIdentifier: HKCategoryTypeIdentifier.sleepAnalysis) {
            // You may want to use a predicate to filter the data... startDate and endDate are NSDate objects corresponding to the time range that you want to retrieve
            //let predicate = HKQuery.predicateForSamplesWithStartDate(startDate,endDate: endDate ,options: .None)
            // Get the recent data first
            let sortDescriptor = NSSortDescriptor(key: HKSampleSortIdentifierEndDate, ascending: false)
            // the block completion to execute
            let query = HKSampleQuery(sampleType: sleepType, predicate: nil, limit: 100000, sortDescriptors: [sortDescriptor]) { (query, tmpResult, error) -> Void in
                if error != nil {
                    // Handle the error in your app gracefully
                    return
                }
                if let result = tmpResult {
                   for item in result {
                        if let sample = item as? HKCategorySample {
                               let startDate = sample.startDate
                               let endDate = sample.endDate
                               print()
                             let sleepTimeForOneDay = sample.endDate.timeIntervalSince(sample.startDate)
                        }
                    }
                }
          }
    }

This gives the array of entry slots. 这给出了入口插槽的阵列。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM