John Ramos John Ramos - 1 year ago 173
Swift Question

Health handles multiple step sources differently than HealthKit—swift

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)


Answer Source

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.