Search code examples
ioshealthkit

Is HKMetadataKeyWasUserEntered broken? I keep getting nil when there is data in the health app


I'm trying to grab data from the Health App. Specifically data that the user did not enter in themselves. For instance, I have an iPhone 6+ that logs the amount of steps that I take. There is also an option to add the data manually; If you add the data manually, the health app marks the data as "user added".

Here's what's confusing me. Let's say I added a step count of 22. When I query the data using HKStatisticsQuery with a predicate of

HKQuery.predicateForObjectsWithMetadataKey(HKMetadataKeyWasUserEntered, allowedValues: [true])

I get the correct result of 22 steps, since I set the allowedValues to true and that I added this myself. However, when I try to set allowedValues to false, I get no results

HKQuery.predicateForObjectsWithMetadataKey(HKMetadataKeyWasUserEntered, allowedValues: [false])

I do indeed have the step data in the health app, but it returned no results.


Solution

  • Check for the below possible areas to fix it:

    1. did you authorized your application to access Steps data from HealthKit?
    2. If your quering for steps count from your application without authorizing with HealthKit, then HealthKit will not return any exception it will simply returns the steps count which was entered from your application only if available, otherwise returns nil.
    3. Before going to query health data, check for the authorization status for steps count using authorizationStatusForType: method available with HKHealthStore class.

    Update 1:

    My observations on wasUserEntered key is:

    1. If user entering steps data from HEALTH app, respective HKQuantitySample stores metadata dictionary along with HKWasUserEntered key as TRUE automatically.
    2. If user entering steps data from other than Apple's HEALTH app, respective health/fitness device or our application should send metadata dictionary with key HKWasUserEntered along with value as either TRUE/FALSE. Otherwise, the metadata property will contain nil object. Hence, Apple is not applying predicate(predicate contains metadata key) on the data which don't have metadata with it.

    For debugging this metadata, try to print your HKQuantitySampleObject.metadata

    Apple's implementation on metadata Vs NSPredicate:

    1. If Health data observed from Health/fitness devices, HealthKit is not adding the metadata dictionary to the respective health record.
    2. In case of Health applications other than Apple's Health app, the developer should manually add the metadata dictionary for his record of health data.
    3. If there is no metadata for a specific health record and NSPredicate have a constraint on metadata then, HealthKit completely omitting to validate such records.

    Finally,

    1. It is advised to use

      • (instancetype)quantitySampleWithType:(HKQuantityType *)quantityType quantity:(HKQuantity *)quantity startDate:(NSDate *)startDate endDate:(NSDate *)endDate metadata:(NSDictionary *)metadata;

    instead of

    + (instancetype)quantitySampleWithType:(HKQuantityType *)quantityType
                                  quantity:(HKQuantity *)quantity
                                 startDate:(NSDate *)startDate
                                   endDate:(NSDate *)endDate;
    

    to add metadata.

    1. Reporting Apple regarding this bug that, predicate(which contains metadata key) should be applied on all the data irrespective of checking for metadata exists or not.