Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Monitor heart rate from HealthKit --> HKAnchoredObjectQuery only called after applicationDidBecomeActive (BUG or FEATURE?)

I am writing a simple app to monitor the heart rate (HKQuantityTypeIdentifierHeartRate) from HealthKit whenever a new health rate value is written to HealthKit.

As seen at WWDC2015 (session 203) I am using a HKAnchoredObjectQuery which should work for adding and deleting objects. Whenever I start the app I am calling the HKQuery for the newest objects and executingQuery which works fine!!! But I am getting no new samples even if the samples are there, but if I bring the app to the background and again to the foreground I am getting all the new heart rates. IS IT A BUG? Or what shall I do to monitor the heart rate without bringing the app to the back- and foreground?

Here is the code I am using (everything is stored in the AppDelegate), I am calling [self requestAccessDataTypes]; from didFinishLaunchingWithOptions:

[healthStore enableBackgroundDeliveryForType:sampleType frequency:HKUpdateFrequencyImmediate withCompletion:^(BOOL success, NSError *error) {}];

HKQuery *query = [self createHeartRateStreamingQuery:datum];
    if (query) {
        [healthStore executeQuery:query];
    }
    else
    {
        NSLog(@"workout can not start");
    }

-(HKQuery*)createHeartRateStreamingQuery:(NSDate*)workoutStartDate
{
    NSLog(@"%@ - createHeartRateStreamingQuery", [self class]);

    if ([HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate]) {
        HKQuantityType *quantityType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate];

        HKAnchoredObjectQuery * heartRateQuery = [[HKAnchoredObjectQuery alloc] initWithType:quantityType predicate:nil anchor:anchor limit:HKObjectQueryNoLimit resultsHandler:^(HKAnchoredObjectQuery * _Nonnull query, NSArray<__kindof HKSample *> * _Nullable sampleObjects, NSArray<HKDeletedObject *> * _Nullable deletedObjects, HKQueryAnchor * _Nullable newAnchor, NSError * _Nullable error) {

            if (!error) {
                anchor = newAnchor;
                [self updateHeartRate:sampleObjects];

            }

        }];
        heartRateQuery.updateHandler = ^void(HKAnchoredObjectQuery *query, NSArray<__kindof HKSample *> * __nullable addedObjects, NSArray<HKDeletedObject *> * __nullable deletedObjects, HKQueryAnchor * __nullable newAnchor, NSError * __nullable error)
        {
            if (!error) {
                anchor = newAnchor;
                [self updateHeartRate:addedObjects];

            }

        };
        return heartRateQuery;
    }
    return nil;
}
like image 480
Ing. Ron Avatar asked Oct 30 '22 16:10

Ing. Ron


1 Answers

You are missing a crucial piece for observing changes in HealthKit. It's called HKObserverQuery.

Docs

Observer queries set up a long-running task on a background queue. This task watches the HealthKit store, and alerts you whenever matching data is saved to or removed from the store. Observer queries let your app respond to changes made by other apps and devices.

Recap:

You have to wrap your HKAnchoredObjectQuery in HKObserverQuery with background delivery enabled in order to get notified about updates. You can then execute your query whenever that happens.

Note 1: HKObserverQuery's update handler will NOT give you any Apple Health data samples. You still have to execute your HKAnchoredObjectQuery with a proper anchor to get the samples.

Note 2: You have to set up HKObserverQuery every time your app launches.

For further info, look at my answer here.

like image 62
damirstuhec Avatar answered Nov 15 '22 05:11

damirstuhec