Health handles multiple step sources differently than HealthKit—swift
Asked Answered
V

1

9

My Swift iOS app connects with HealthKit to show the user how many steps they have taken so far in the day. For the most part, this is successful. When the sole source of steps is steps recorded by the iPhone's built-in pedometer function, everything works fine and the step count shown by my app matches with the Health app's step count. However, when there are multiple sources of data—on my personal iPhone, my Pebble Time smartwatch and the iPhone's pedometer both feed steps to Health—my app freaks out, recording all the steps from both. Whereas the iOS Health app roots out duplicate steps (which it can do because both my iPhone and my Pebble report steps to Health every 60 seconds) and shows an accurate daily step count, the data my app gets from HealthKit includes all the steps from both sources, causing great inaccuracies.

How can I tap into the Health app's final result, where the step count is accurate, instead of tapping into HealthKit's stream of over-inflated step data?

UPDATE: Here's the code I use to get daily health data:

func recentSteps2(completion: (Double, NSError?) -> () )
    {

        checkAuthorization() // checkAuthorization just makes sure user is allowing us to access their health data.
        let type = HKSampleType.quantityTypeForIdentifier(HKQuantityTypeIdentifierStepCount) // The type of data we are requesting


        let date = NSDate()
        let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
        let newDate = cal.startOfDayForDate(date)
        let predicate = HKQuery.predicateForSamplesWithStartDate(newDate, endDate: NSDate(), options: .None) // Our search predicate which will fetch all steps taken today

        // The actual HealthKit Query which will fetch all of the steps and add them up for us.
        let query = HKSampleQuery(sampleType: type!, predicate: predicate, limit: 0, sortDescriptors: nil) { query, results, error in
            var steps: Double = 0

            if results?.count > 0
            {
                for result in results as! [HKQuantitySample]
                {
                    steps += result.quantity.doubleValueForUnit(HKUnit.countUnit())
                }
            }

            completion(steps, error)
        }

        storage.executeQuery(query)
    }
Vermicelli answered 11/4, 2016 at 22:25 Comment(2)
Please include a code snippet demonstrating how you calculate the number of steps the user is taking. What type of query are you using?Elseelset
@Elseelset I updated my question to include the code I use to calculate user's steps.Vermicelli
E
17

Your code is over-counting steps because it simply sums the results of an HKSampleQuery. A sample query will return all samples matching the given predicate, including overlapping samples from multiple sources. If you wanted to accurately compute the user's step count using HKSampleQuery, you'd have to detect overlapping samples and avoid counting them, which would be tedious and difficult to do correctly.

Health uses HKStatisticsQuery and HKStatisticsCollectionQuery to compute aggregate values. These queries calculate the sum (and other aggregate values) for you, and do so efficiently. Most importantly, though, they de-duplicate overlapping samples to avoid over-counting.

The documentation for HKStatisticsQuery includes sample code.

Elseelset answered 12/4, 2016 at 20:35 Comment(5)
Thanks! Can I have a little more information about HKStatisticsQuery? Maybe a code sample or a link to a tutorial (I searched google and it's pretty sparse)?Vermicelli
Did you try looking at the sample code in the reference documentation? developer.apple.com/library/ios/documentation/HealthKit/…Elseelset
Did you get this working? We are having the same problem with steps collected with FitBit and steps collected with the iPhone.Disgruntle
Good point. We're counting asleep minutes in our app, and unfortunately couldn't find an easy way to deduplicate those, because the sleep analysis is a Category Type in HealthKit, and that means you cannot use HKStatistics queries for those. Do you have any suggestions of how to solve this problem, or making plain HKSample queries and then comparing startDate / endDate is the only way? ThanksUrinary
@IgorVasilev the approach you described is the best way to handle sleep data since as you said there is no equivalent of HKStatisticsCollectionQuery that handles sleep.Elseelset

© 2022 - 2024 — McMap. All rights reserved.