Monitor heart rate from HealthKit --> HKAnchore

2019-03-29 23:13发布

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

2条回答
Luminary・发光体
2楼-- · 2019-03-29 23:46

Right now (iOS 9.1, WatchOS 2.0.1), it is not possible to get the latest data from HealthKit through an iOS app. It was possible in the WWDC demo because the code was running on the WatchOS app's ExtensionDelegate rather than on the iOS app. There is a rdar bug report filed here.

To get the latest data on iOS, it's not possible without creating a WatchOS app. With a WatchOS app you could use a Workout Session and Watch Connectivity to send heart rate data to the iOS app every time it changes.

Of course, this doesn't help if your heart rate data isn't coming from an Apple Watch. Hopefully it'll be fixed in an upcoming release.

查看更多
Deceive 欺骗
3楼-- · 2019-03-30 00:05

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.

查看更多
登录 后发表回答