HealthKit cannot read steps data - ios

I'm working with HealthKit to read steps data from my iOS device.
here is my code:
if ([HKHealthStore isHealthDataAvailable]) {
__block double stepsCount = 0.0;
self.healthStore = [[HKHealthStore alloc] init];
NSSet *stepsType =[NSSet setWithObject:[HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]];
[self.healthStore requestAuthorizationToShareTypes:nil readTypes:stepsType completion:^(BOOL success, NSError * _Nullable error) {
if (success) {
HKSampleType *sampleType = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount];
HKSampleQuery *sampleQuery = [[HKSampleQuery alloc] initWithSampleType:sampleType predicate:nil limit:HKObjectQueryNoLimit sortDescriptors:nil resultsHandler:^(HKSampleQuery *query, NSArray *results, NSError *error) {
if (error != nil) {
NSLog(#"results: %lu", (unsigned long)[results count]);
for (HKQuantitySample *result in results) {
stepsCount += [result.quantity doubleValueForUnit:[HKUnit countUnit]];
}
NSLog(#"Steps Count: %f", stepsCount);
} else {
NSLog(#"error:%#", error);
}];
[self.healthStore executeQuery:sampleQuery];
[self.healthStore stopQuery:sampleQuery];
NSLog(#"steps:%f",stepsCount);
}
}];
}
I build and run the code on an iPhone6 which does have steps data and in the Settings -> Privacy -> Health, the app does have been allowed to read data, but the log area only shows:
steps:0.000000
I put a break point on the for-loop and on the NSLog(#"error:%#", error), but the app does not break.
Anybody can help?

Try this code u just change the start date and End date.
-(void) getQuantityResult
{
NSInteger limit = 0;
NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:currentDate endDate:[[NSDate date]dateByAddingTimeInterval:60*60*24*3] options:HKQueryOptionStrictStartDate];
NSString *endKey = HKSampleSortIdentifierEndDate;
NSSortDescriptor *endDate = [NSSortDescriptor sortDescriptorWithKey: endKey ascending: NO];
HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType[HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]
predicate: predicate
limit: limit
sortDescriptors: #[endDate]
resultsHandler:^(HKSampleQuery *query, NSArray* results, NSError *error){
dispatch_async(dispatch_get_main_queue(), ^{
// sends the data using HTTP
int dailyAVG = 0;
for(HKQuantitySample *samples in results)
{
dailyAVG += [[samples quantity] doubleValueForUnit:[HKUnit countUnit]];
}
lblPrint.text = [NSString stringWithFormat:#"%d",dailyAVG];
NSLog(#"%#",lblPrint.text);
NSLog(#"%#",#"Done");
});
}];
[self.healthStore executeQuery:query];
}

Your code stops the query immediately, before it has a chance to run. For this query, there is no reason to call stopQuery: at all unless you want to cancel a query before it finishes. Since the query is not long lived (it doesn't have an updateHandler), it will stop immediately after the resultsHandler is called.
The second problem is that your code attempts to log step count too soon. The query runs asynchronously, and the resultsHandler will be called on a background thread once the query completes. I'd suggest logging stepsCount inside the block.
Finally, if you want to count the user's steps you should us an HKStatisticsQuery instead of summing the results of an HKSampleQuery. HKStatisticsQuery is more efficient and will yield correct results when there are multiple sources of overlapping data in HealthKit. Your current implementation will double count the user's steps if they have both an iPhone and an Apple Watch, for instance.

Related

Getting updated heart rate data from Health Kit

I wrote this code to get heart rate I am using NSArray and getting average of heart rate.
Now the question is the Apple Watch is updating data in Health Kit and I want the updated average heart beats being refreshed at every 1 minutes.
I am stuck at this point, please help?
-(double)get_heartRates
{
//code to get the updated heart beats
NSDate *startDate1 = [NSDate distantPast];
NSPredicate *Predicate = [HKQuery predicateForSamplesWithStartDate:startDate1 endDate:[NSDate date] options:HKQueryOptionStrictEndDate];
HKSampleType *object = [HKSampleType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate];
sum_Of_HeartRates=0.0;
HKAnchoredObjectQuery *heartQuery = [[HKAnchoredObjectQuery alloc] initWithType:object predicate:Predicate anchor:self.lastAnchor limit:0 resultsHandler:^(HKAnchoredObjectQuery *query, NSArray<HKSample *> *sampleObjects, NSArray<HKDeletedObject *> *deletedObjects, HKQueryAnchor *newAnchor, NSError *error) {
NSLog(#"Sample counts:%ld",sampleObjects.count);
for(int i=0;i<(int)sampleObjects.count;i++)
{
HKQuantitySample *sample = (HKQuantitySample *)[sampleObjects objectAtIndex:i];
HKQuantity *quantity = sample.quantity;
double bpm_Values= [quantity doubleValueForUnit:[HKUnit unitFromString:#"count/min"]];
sum_Of_HeartRates=sum_Of_HeartRates+bpm_Values;
}
avg_heartBeats=sum_Of_HeartRates/(int)sampleObjects.count;
}];
[heartQuery setUpdateHandler:^(HKAnchoredObjectQuery *query, NSArray<HKSample *> *SampleArray, NSArray<HKDeletedObject *> *deletedObjects, HKQueryAnchor *Anchor, NSError *error) {
HKQuantitySample *sample = (HKQuantitySample *)[SampleArray objectAtIndex:0];
HKQuantity *quantity = sample.quantity;
new_Updated_Data =[quantity doubleValueForUnit:[HKUnit unitFromString:#"count/min"]];
NSLog(#"new quantity:%f",new_Updated_Data);
}];
[self.healthStore executeQuery:heartQuery];
NSLog(#"updated data %f",new_Updated_Data);
return avg_heartBeats;
//todo:- to get background update fast and easy
}
Use HKObserverQuery to get a long running query that is updated in background:
https://developer.apple.com/library/ios/documentation/HealthKit/Reference/HKObserverQuery_Class/index.html
As long as no HKWorkoutSessionis running, your watch measures the heart rate every 10 minutes, so you don't get more values. When a HKWorkoutSession is running on your watch, you get values more frequently.
If you want to dive into HKWorkoutSession, Allan has a detailed tutorial: https://developer.apple.com/videos/play/wwdc2015/203/

HKAnchoredObjectQuery results handler doesn't fire after initial results

Our fitness app was using three anchored object queries to stream heart rate, active calories and distance; it was working just fine until a few weeks ago when we started optimizing the rest of the app's performance to be more responsive and query samples for past workouts. We believe we've restored the queries back to the way they were before, and we have very similar code but written in Swift for a separate fitness app working fine, but these HKAnchoredObjectQuerys just don't return further results after the initial results are handled (yes, a workout session is active). We're a bit stumped. Can anyone take a look and suggest where we might have gone wrong?
Thank you!
Here's an example of the heart rate query:
- (HKQuery*) createHeartRateStreamingQuery: (NSDate *) workoutStartDate {
NSPredicate * predicate = [HKQuery predicateForSamplesWithStartDate:workoutStartDate endDate:nil options:HKQueryOptionNone];
HKQueryAnchor *anchor = HKAnchoredObjectQueryNoAnchor;
if (_HRAnchor) {
anchor = _HRAnchor;
}
HKQuantityType * quantityType = [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierHeartRate];
HKAnchoredObjectQuery *query =
[[HKAnchoredObjectQuery alloc]
initWithType:quantityType
predicate:predicate
anchor:anchor
limit:HKObjectQueryNoLimit
resultsHandler:^(HKAnchoredObjectQuery * query,
NSArray<HKSample *> * sampleObjects,
NSArray<HKDeletedObject *> * deletedObjects,
HKQueryAnchor * newAnchor,
NSError * error) {
if (error) {
NSLog(#"*** %s An error occured while performing the heartrate anchored object query. %# ***",
__PRETTY_FUNCTION__, error.localizedDescription);
abort();
} else {
if (newAnchor) {
_HRAnchor = newAnchor;
NSLog(#"*** %s: %i samples returned for startDate %# ***", __PRETTY_FUNCTION__, sampleObjects.count, workoutStartDate);
for (HKQuantitySample *sample in sampleObjects) {
[self updateHeartRate:sample];
}
for (HKDeletedObject *sample in deletedObjects) {
// [self removeHRSamples: sample]; //not using this for now
}
}
}
}];
return query;
}
- (void) updateHeartRate: (HKQuantitySample *) HRSample {
NSLog(#"%s: %#", __PRETTY_FUNCTION__, HRSample);
[_workoutHRSamplesArray addObject: HRSample];
}
In order to stream samples using an HKAnchoredObjectQuery, you must set the updateHandler property on the query. The results handler you provided to the initializer is only intended to run once for the existing samples that match your query.

iOS Healthkit reading workouts

Hi any one know how to fetch workouts data from HealthKit. i have seen in this tutorial http://www.raywenderlich.com/89733/healthkit-tutorial-with-swift-workouts it is in swift. i have tried in objective c based on that tutorial but getting results zero. there are questions for saving workouts but i want to read workouts data and display.
HKWorkoutType *workouttype = [HKWorkoutType workoutType];
HKWorkout *workout;
NSDate *startDate, *endDate;
NSDate *date1 = [NSDate date];
int daysTominus = -2;
startDate = [date1 dateByAddingTimeInterval:60*60*24*daysTominus];
int daysToAdd = 1;
NSDate *newDate1 = [date1 dateByAddingTimeInterval:60*60*24*daysToAdd];
endDate = newDate1;
workout = [HKWorkout workoutWithActivityType:HKWorkoutActivityTypeSwimming startDate:startDate endDate:endDate];
NSPredicate *predicate = [HKQuery predicateForObjectsFromWorkout:workout];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:HKSampleSortIdentifierStartDate ascending:YES];
HKSampleQuery *sampleQuery = [[HKSampleQuery alloc] initWithSampleType:workouttype
predicate:predicate
limit:HKObjectQueryNoLimit
sortDescriptors:#[sortDescriptor]
resultsHandler:^(HKSampleQuery *query, NSArray *results, NSError *error)
{
if(!error && results){
for(HKQuantitySample *samples in results)
{
// your code here
NSLog(#"%#",samples);
}
}
}];
// Execute the query
[healthStore executeQuery:sampleQuery];
The problem seems to be your predicate.
This code works for me, I used running because I don't have swimming data but you can change it back to swimming:
-(void)retrieveWorkouts{
// 1. Predicate to read only running workouts
NSPredicate *predicate = [HKQuery predicateForWorkoutsWithWorkoutActivityType:HKWorkoutActivityTypeWalking];
// 2. Order the workouts by date
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]initWithKey:HKSampleSortIdentifierStartDate ascending:false];
// 3. Create the query
HKSampleQuery *sampleQuery = [[HKSampleQuery alloc] initWithSampleType:[HKWorkoutType workoutType]
predicate:predicate
limit:HKObjectQueryNoLimit
sortDescriptors:#[sortDescriptor]
resultsHandler:^(HKSampleQuery *query, NSArray *results, NSError *error)
{
if(!error && results){
NSLog(#"Retrieved the following workouts");
for(HKQuantitySample *samples in results)
{
// your code here
HKWorkout *workout = (HKWorkout *)samples;
NSLog(#"%f",workout);
}
}else{
NSLog(#"Error retrieving workouts %#",error);
}
}];
// Execute the query
[healthStore executeQuery:sampleQuery];
}

CKFetchRecordsOperation + CKQueryOperations ... what am I missing?

Managed to cobble together a CKFetchRecordsOperation after much searching for sample code; and here it is... but I must have missed something. Don't get me wrong it works a treat... but...
To execute a CKFetchRecordsOperation you need an NSArray of CKRecordIDs; to get a NSArray of CKRecordIDs, you need to execute CKQuery thru which you can build your NSArray of CKRecordIDs.
But wait a minute, the process of extracting the CKRecordIDs uses a CKQuery, thru which I could simply download the CKRecords anyway?
How do you get your NSArray of CKRecordIDs if not with a CKQuery?
-(void)doSingleBeaconsDownload
{
CKDatabase *publicDatabase = [[CKContainer containerWithIdentifier:#"iCloud.cqd.ch.BeaconBrowser"] publicCloudDatabase];
NSPredicate *predicatex = [NSPredicate predicateWithFormat:#"iBeaconConfig = %#",iBeaconsConfirmed.giReferenceID];
CKQuery *query = [[CKQuery alloc] initWithRecordType:#"Running" predicate:predicatex];
[self.delegate performSelectorOnMainThread:#selector(processCompleted:) withObject:#"Downloading Configuration ..." waitUntilDone:YES];
[publicDatabase performQuery:query inZoneWithID:nil completionHandler:^(NSArray *results, NSError *error) {
if (error) {
NSLog(#"Batch Download Error iCloud error %#",error);
}
else {
NSMutableArray *rex2download = [[NSMutableArray alloc] init];
for (CKRecord *rex in results) {
[rex2download addObject:rex.recordID];
}
CKFetchRecordsOperation *fetchRecordsOperation = [[CKFetchRecordsOperation alloc] initWithRecordIDs:rex2download];
/* fetchRecordsOperation.perRecordCompletionBlock = ^(CKRecord *record, CKRecordID *recordID, NSError *error) {
if (error) {
// Retain the record IDs for failed fetches
}
else {
// Do something with each record downloaded
}
};*/
fetchRecordsOperation.perRecordProgressBlock = ^(CKRecordID *record, double recordsDownloaded) {
if (error) {
// damn ...
} else {
NSLog(#"Downloaded %f", recordsDownloaded);
}
};
fetchRecordsOperation.fetchRecordsCompletionBlock = ^(NSDictionary *recordsByRecordID, NSError *error) {
if (error) {
// Failed to fetch all or some of the records
}
else {
for(CKRecord *record in results) {
NSLog(#"Fini download %lu",(unsigned long)[recordsByRecordID count]);
}
[self.delegate performSelectorOnMainThread:#selector(beaconsDownloaded:) withObject:noOf waitUntilDone:YES];
}
};
[publicDatabase addOperation:fetchRecordsOperation];
}
}];
}
From Apple Documentation: A CKFetchRecordsOperation object retrieves CKRecord objects (whose IDs you already know) from iCloud.
A CKQueryOperation is used to retrieve CKRecords from iCloud based on some Query, so you can get them even if you do not know their recordIDs. A CKFetchRecordsOperation is used ONLY when you have the CKRecordIDs. You can create a CKRecordID without accessing iCloud, and you can store them in any local storage you have.
A good use case, which I use for this kind of operation, is when you want to modify a CKRecord, you need to first retrieve it from iCloud (using CKFetchRecordsOperation) and then save it back using CKModifyRecordsOperation.
Have a look at the two WWDC 2014 Videos on CloudKit that explain this pretty well.
Thanks for your help! I managed to craft an CKQueryOperation into the code, but ... but my code is soon going be become unreadable with many more of these nested loops? Surely there is a more elegant way to link CKQuery/Fetch/Modify operations; tried dependancies but missing something still ?
-(void)doSingleBeaconsDownload
{
[self.delegate performSelectorOnMainThread:#selector(processCompleted:) withObject:#"Downloading Configuration ..." waitUntilDone:YES];
CKDatabase *publicDatabase = [[CKContainer containerWithIdentifier:#"iCloud.cqd.ch.BeaconBrowser"] publicCloudDatabase];
NSPredicate *predicatex = [NSPredicate predicateWithFormat:#"iBeaconConfig = %#",iBeaconsConfirmed.giReferenceID];
CKQuery *query = [[CKQuery alloc] initWithRecordType:#"Running" predicate:predicatex];
CKQueryOperation *queryOp =[[CKQueryOperation alloc] initWithQuery:query];
queryOp.desiredKeys = #[#"record.recordID.recordName"];
queryOp.resultsLimit = CKQueryOperationMaximumResults;
NSMutableArray *rex2download = [[NSMutableArray alloc] init];
queryOp.recordFetchedBlock = ^(CKRecord *results)
{
[rex2download addObject:results.recordID];
};
queryOp.queryCompletionBlock = ^(CKQueryCursor *cursor, NSError *error)
{
// Cursor it seems contains a reference to a second call to it [required] if you try download more then 100 records
if (error) {
NSLog(#"Batch Download Error iCloud error %#",error);
}
else {
CKFetchRecordsOperation *fetchRecordsOperation = [[CKFetchRecordsOperation alloc] initWithRecordIDs:rex2download];
fetchRecordsOperation.perRecordCompletionBlock = ^(CKRecord *record, CKRecordID *recordID, NSError *error) {
if (error) {
// Retain the record IDs for failed fetches
}
else {
// Do something ..
}
};
fetchRecordsOperation.perRecordProgressBlock = ^(CKRecordID *record, double recordsDownloaded) {
if (error) {
// damn
} else {
NSLog(#"Downloaded X");
}
};
fetchRecordsOperation.fetchRecordsCompletionBlock = ^(NSDictionary *recordsByRecordID, NSError *error) {
if (error) {
// Failed to fetch all or some of the records
}
else {
… Final clean up
}
};
[publicDatabase addOperation:fetchRecordsOperation];
}
};
[publicDatabase addOperation:queryOp];
}
Thanks Harry; Here is my third and final working solution; used a singleton global variable to pass the data between the two CKQueryOperations; don't know if that is best/good practice, but it works
... seems a pity you cannot use something like this ...
[fetchRecordsOperation addDependency:queryOp]; &
[queue fetchRecordsOperation]; (doesn't compile)
Would be a far cleaner solution... anyway here is V3 for completeness..
-(void)doSingleBeaconsDownloadV3
{
NSLog(#"doQuery executing");
CKDatabase *publicDatabase = [[CKContainer containerWithIdentifier:#"iCloud.cqd.ch.BeaconBrowser"] publicCloudDatabase];
NSPredicate *predicatex = [NSPredicate predicateWithFormat:#"iBeaconConfig = %#",iBeaconsConfirmed.giReferenceID];
CKQuery *query = [[CKQuery alloc] initWithRecordType:#"Running" predicate:predicatex];
CKQueryOperation *queryOp =[[CKQueryOperation alloc] initWithQuery:query];
queryOp.desiredKeys = #[#"record.recordID.recordName"];
queryOp.resultsLimit = CKQueryOperationMaximumResults;
//NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"creationDate" ascending:NO];
//query.sortDescriptors = #[sortDescriptor];
queryOp.recordFetchedBlock = ^(CKRecord *results)
{
[iBeaconsConfirmed.giRex2Download addObject:results.recordID];
NSLog(#"fetched %lu",[iBeaconsConfirmed.giRex2Download count]);
};
queryOp.queryCompletionBlock = ^(CKQueryCursor *cursor, NSError *error)
{
if (error) {
NSLog(#"Batch Download Error iCloud error %#",error);
} else {
NSLog(#"fetched %lu",[iBeaconsConfirmed.giRex2Download count]);
[self DoFetchV2];
}
};
[publicDatabase addOperation:queryOp];
}
-(void)DoFetchV2
{
NSLog(#"dofetch executing %lu",[iBeaconsConfirmed.giRex2Download count]);
CKDatabase *publicDatabase = [[CKContainer containerWithIdentifier:#"iCloud.cqd.ch.BeaconBrowser"] publicCloudDatabase];
CKFetchRecordsOperation *fetchRecordsOperation = [[CKFetchRecordsOperation alloc] initWithRecordIDs:iBeaconsConfirmed.giRex2Download];
fetchRecordsOperation.perRecordCompletionBlock = ^(CKRecord *record, CKRecordID *recordID, NSError *error) {
if (error) {
// Retain the record IDs for failed fetches
}
else {
// Do something useful with data
}
};
fetchRecordsOperation.perRecordProgressBlock = ^(CKRecordID *record, double recordsDownloaded)
{
NSLog(#"Downloaded X");
};
fetchRecordsOperation.fetchRecordsCompletionBlock = ^(NSDictionary *recordsByRecordID, NSError *error) {
if (error) {
// Failed to fetch all or some of the records
} else {
NSLog(#"Fini download %lu",(unsigned long)[recordsByRecordID count]);
}
};
[publicDatabase addOperation:fetchRecordsOperation];
}

Heart Rate data monthly

I am retrieving heart rate from Health Kit in my app. however i get the latest data from Health Kit, how can i get the data monthly wise? I mean last reading from each month.. i saw NSPredicate can be used to do so but i am not getting exactly how to do it..!! I am new to it, please help.!!
here is my code to access heart rate:
NSSortDescriptor *timeSortDescriptor = [[NSSortDescriptor alloc] initWithKey:HKSampleSortIdentifierEndDate ascending:NO];
HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:quantityType predicate:predicate limit:HKObjectQueryNoLimit sortDescriptors:#[timeSortDescriptor] resultsHandler:^(HKSampleQuery *query, NSArray *results, NSError *error) {
if (!results) {
if (completion)
{
completion(nil, error);
}
return;
}
if (completion) {
// If quantity isn't in the database, return nil in the completion block.
HKQuantitySample *quantitySample = results.firstObject;
HKQuantity *quantity = quantitySample.quantity;
completion(quantity, error);
}
}];
[self executeQuery:query];
Code for predicate:
NSDate *startDate = [NSDate dateWithYear:[NSNumber numberWithInt:2015] month:[NSNumber numberWithInt:1] day:[NSNumber numberWithInt:1] hour:[NSNumber numberWithInt:00] minute:[NSNumber numberWithInt:00] seconds:[NSNumber numberWithInt:00]];
NSDate *endDate = [NSDate dateWithYear:[NSNumber numberWithInt:2015] month:[NSNumber numberWithInt:30] day:[NSNumber numberWithInt:1] hour:[NSNumber numberWithInt:00] minute:[NSNumber numberWithInt:00] seconds:[NSNumber numberWithInt:59]];
NSPredicate *explicitTimeInterval =
[NSPredicate predicateWithFormat:#"%K >= %# AND %K < %#",
HKPredicateKeyPathEndDate, startDate,
HKPredicateKeyPathStartDate, endDate];
self.healthStore = [[HKHealthStore alloc]init];
Thanks in advance :)

Resources