Adding Diet calories to health kit on iPhone does not update on watch App health kit - apple-watch

I have a an iPhone app with an accompanying watch OS 2 application.
Both iPhone and watch app can successfully write and query diet calorie info from health kit.
If I write diet calorie info from the watch up and then query health store for the same, i get the correct results back.
However If I write Diet calorie info from the iPhone app or enter it manually on the on health app , the watch query results never get the new entries.
Reading and writing health kit data is based on the FIT example here https://github.com/ooper-shlab/Fit-Swift/tree/master/Fit
func addFoodItem(calories: Double, completion: ((NSError?) -> Void)?){
let nowDate: NSDate = NSDate()
let energyQuantityConsumed: HKQuantity = HKQuantity(unit: HKUnit.kilocalorieUnit(), doubleValue: calories)
let energyConsumedType: HKQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierDietaryEnergyConsumed)!
let energyConsumedSample: HKQuantitySample = HKQuantitySample(type: energyConsumedType, quantity: energyQuantityConsumed, startDate: nowDate, endDate: nowDate)
let energyConsumedSamples: Set<HKSample> = [energyConsumedSample]
let foodType: HKCorrelationType = HKCorrelationType.correlationTypeForIdentifier(HKCorrelationTypeIdentifierFood)!
let foodCorrelation: HKCorrelation = HKCorrelation(type: foodType, startDate: nowDate, endDate: nowDate, objects: energyConsumedSamples)
let completion: (Bool, NSError?) -> Void = {
(success, error) -> Void in
if completion != nil {
completion!( error)
}
}
self.healthStore.saveObject(foodCorrelation, withCompletion: completion)
}
func fetchSumOfSamplesTodayForType(quantityType : HKQuantityType , unit: HKUnit, options: HKStatisticsOptions, forDay : Int, completion: ((Double, NSError?) -> Void)?) {
let predicate = self.predicateForSamplesToday(forDay)
let query: HKStatisticsQuery = HKStatisticsQuery(quantityType: quantityType, quantitySamplePredicate: predicate, options: options) {
(_query, result, error) -> Void in
let sum: HKQuantity? = result?.sumQuantity()
if completion != nil {
let value: Double = sum?.doubleValueForUnit(unit) ?? 0.0
completion!(value, error)
}
}
self.healthStore.executeQuery(query)
}
Is any experiencing the same problems or have any suggestions to fix ?

The HealthKit database on the watch only contains data that originated on the watch. It does not include samples from the companion phone.

Related

Fetching results with a list of CKQuery

I have a CKRecord of recipes that gets fetched to an iOS app. Once I have that list, I need to prioritize the results of recipes that are the highest suggested "likedIds" which is a list of integers representing recipe_ids (please see my dataset image below), then display the remaining recipes below that. I can't merely sort by highest rated recipes because I'm using collaborative filtering elsewhere in the project to suggest specific recipes over others, but I still want to list them all.
Here in this code below I am appending the results of NSPredicates to a list of CKQuery called 'queries'. Now that I have that [CKquery], what do I do with it? How do I fetch the results I need? Which method do I use, if publicDB.perform() isn't the right method (since I get an 'expected argument type' error)? Below, I tried using a for loop inside of the AttachToMainThread() function that I wrote, but I get 3 different random results at refresh, recipes in the "likedIds" list, recipes not the "likedIds" list, or nothing at all, yet no SIGABRT errors which is nice.
TL;DR
What do I do with my CKquery list to fetch results?
Thank you for your time!
Just the code focusing on the primary subject:
import Foundation
import CloudKit
class Model {
// MARK: - iCloud Info
let container: CKContainer
let publicDB: CKDatabase
private(set) var recipes: [Recipe] = []
static var currentModel = Model()
init() {
container = CKContainer.default()
publicDB = container.publicCloudDatabase
privateDB = container.privateCloudDatabase
}
#objc func refresh(_ completion: #escaping (Error?) -> Void) {
var queries = [CKQuery] ()
// Function that returns a CKQuery
let likedQuery = GetRecipesWithLikedIds()
queries.append(likedQuery)
// Function that returns a CKQuery
let unlikedQuery = GetRecipesWithoutLikedIds()
queries.append(unlikedQuery)
AttachToMainThread(forQuery: queries, completion)
}
private func AttachToMainThread(forQuery queries: [CKQuery],
_ completion: #escaping (Error?) -> Void) {
for q in queries {
publicDB.perform(q,
inZoneWith: CKRecordZone.default().zoneID) { [weak self] results, error in
guard let self = self else { return }
if let error = error {
DispatchQueue.main.async {
completion(error)
}
return
}
guard let results = results else { return }
self.recipes = results.compactMap {
Recipe(record: $0, database: self.publicDB)
}
DispatchQueue.main.async {
completion(nil)
}
}
}
}
}
My entire code:
import Foundation
import CloudKit
class Model {
// MARK: - iCloud Info
let container: CKContainer
let publicDB: CKDatabase
var carbohydrate = "rice"
var vegetable = "tomatoes"
// MARK: - Properties
private(set) var recipes: [Recipe] = []
static var currentModel = Model()
init() {
container = CKContainer.default()
publicDB = container.publicCloudDatabase
privateDB = container.privateCloudDatabase
}
#objc func refresh(_ completion: #escaping (Error?) -> Void) {
var queries = [CKQuery] ()
let likedQuery = GetRecipesWithLikedIds()
queries.append(likedQuery)
let unlikedQuery = GetRecipesWithoutLikedIds()
queries.append(unlikedQuery)
AttachToMainThread(forQuery: queries, completion)
}
private func AttachToMainThread(forQuery queries: [CKQuery],
_ completion: #escaping (Error?) -> Void) {
for q in queries {
publicDB.perform(q,
inZoneWith: CKRecordZone.default().zoneID) { [weak self] results, error in
guard let self = self else { return }
if let error = error {
DispatchQueue.main.async {
completion(error)
}
return
}
guard let results = results else { return }
self.recipes = results.compactMap {
Recipe(record: $0, database: self.publicDB)
}
for r in self.recipes {
self.PrettyPrintRecipes(rName: r.name, rId: String(r.recipe_id), rIng: r.ingredients)
}
DispatchQueue.main.async {
completion(nil)
}
}
}
}
func GetRecipesWithLikedIds() -> CKQuery {
let searchTextA: [String] = [carbohydrate," "+carbohydrate,carbohydrate+"s",carbohydrate+"es"]
let subPred1 = NSPredicate (format: "ANY ingredients IN %#",argumentArray: [searchTextA])
let searchTextB: [String] = [vegetable," "+vegetable,vegetable+"s",vegetable+"es"]
let subPred2 = NSPredicate (format: "ANY ingredients IN %#",argumentArray: [searchTextB])
let likedIds: [Int] = [13733,32441]
let subPred3 = NSPredicate (format: "NOT (recipe_id IN %#)", likedIds)
let and_pred1 = NSCompoundPredicate(andPredicateWithSubpredicates: [subPred1, subPred2])
let and_pred2 = NSCompoundPredicate(andPredicateWithSubpredicates: [subPred3])
let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [and_pred1, and_pred2])
return CKQuery(recordType: "Recipe", predicate: predicate)
}
func GetRecipesWithoutLikedIds() -> CKQuery {
let searchTextA: [String] = [carbohydrate," "+carbohydrate,carbohydrate+"s",carbohydrate+"es"]
let subPred1 = NSPredicate (format: "ANY ingredients IN %#",argumentArray: [searchTextA])
let searchTextB: [String] = [vegetable," "+vegetable,vegetable+"s",vegetable+"es"]
let subPred2 = NSPredicate (format: "ANY ingredients IN %#",argumentArray: [searchTextB])
let likedIds: [Int] = [13733,32441]
let subPred3 = NSPredicate (format: "recipe_id IN %#",argumentArray: [likedIds])
let and_pred1 = NSCompoundPredicate(andPredicateWithSubpredicates: [subPred1, subPred2])
let and_pred2 = NSCompoundPredicate(andPredicateWithSubpredicates: [subPred3])
let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [and_pred1, and_pred2])
return CKQuery(recordType: "Recipe", predicate: predicate)
}
func PrettyPrintRecipes(rName: String, rId: String, rIng: [String]) {
print("Name: "+rName)
print("Recipe_id: "+rId)
print("Ingredients:")
for s in 0..<rIng.count {
print("\t"+String(s)+": "+rIng[s])
}
}
public func printVegetable(){
print(vegetable)
}
}
An Example Image of my Dataset

HealthKit Workout data

I wrote this function to get the degree Celsius value during a workout. How can I get the workout name/ heartbeat etc.?
func getWorkoutWeather(workout: HKWorkout) -> Double {
if let metadata = workout.metadata {
if let mataTemperature = metadata[HKMetadataKeyWeatherTemperature] {
if let quantityTemperature = mataTemperature as? HKQuantity {
let celsius = quantityTemperature.doubleValue(for: HKUnit.degreeCelsius())
print(celsius)
return celsius
}
}
}
We need to create a separate query for each data type associated with the workout. For example, to get the full details of the workout created earlier, we would need separate queries for distance, energy burned, and heart rate etc.
Query to get the Heart rate.
class func loadheartRateWorkouts(completion:
#escaping ([HKWorkout]?, Error?) -> Void) {
guard let heartRateType =
HKObjectType.quantityType(forIdentifier:
HKQuantityTypeIdentifier.heartRate) else {
fatalError("*** Unable to create a Heart rate type ***")
}
// Get all workouts that only came from this app.
let workoutPredicate = HKQuery.predicateForObjects(from: .default())
let startDateSort = NSSortDescriptor(key: HKSampleSortIdentifierStartDate, ascending: true)
let query = HKSampleQuery(sampleType: heartRateType,
predicate: workoutPredicate,
limit: 0,
sortDescriptors: [startDateSort]) { (sampleQuery, results, error) -> Void in
guard let heartRateSamples = results as? [HKQuantitySample] else {
// Perform proper error handling here.
return
}
// Use the workout's Heart rate samples here.
}
HKHealthStore().execute(query)
}
Reference: Fetching samples from the Workout

Step Count always "0" using healthKit in swift

I am trying to get last 7 days step count but it is always coming zero. But when I open the health app in iPhone then it is more than 3000 steps. Even I also added property Privacy - Health Share Usage Description and Privacy - Health Update Usage Description in .plist file.
Here is my code
var healthScore = HKHealthStore()
override func viewDidLoad() {
super.viewDidLoad()
// Access Step Count
let healthKitTypes: Set = [ HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount)! ]
// Check for Authorization
healthScore.requestAuthorization(toShare: healthKitTypes, read: healthKitTypes) { (bool, error) in
if (bool) {
// Authorization Successful
self.getSteps { (result) in
DispatchQueue.main.async {
let stepCount = String(Int(result))
self.stepLbl.text = String(stepCount)
}
}
}
}
}
func getSteps(completion: #escaping (Double) -> Void){
let stepsQuantityType = HKQuantityType.quantityType(forIdentifier: .stepCount)!
let now = Date()
let exactlySevenDaysAgo = Calendar.current.date(byAdding: DateComponents(day: -7), to: now)!
let predicate = HKQuery.predicateForSamples(withStart: exactlySevenDaysAgo, end: now, options: .strictStartDate)
let query = HKStatisticsQuery(quantityType: stepsQuantityType, quantitySamplePredicate: predicate, options: .cumulativeSum) { (_, result, error) in
var resultCount = 0.0
guard let result = result else {
print("\(String(describing: error?.localizedDescription)) ")
completion(resultCount)
return
}
if let sum = result.sumQuantity() {
resultCount = sum.doubleValue(for: HKUnit.count())
}
DispatchQueue.main.async {
completion(resultCount)
}
}
healthScore.execute(query)
}
In console I checked the dates are also correct now here's the screenshot

How do I get this the currentStandHour value in Apple Watch iOS?

I want to retrieve the value that indicates whether or not the user has stood this hour. I also want to be able to retrieve the StandHours count for the day.
Here are the Apple links that I've been trying to understand in order get the value from HealthKit. I provide these links to help provide understanding for what I'm looking for and also to help you answer my question.
appleStandHour type property: https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier/1615539-applestandhour
HealthKit category type identifier: https://developer.apple.com/documentation/healthkit/hkcategorytypeidentifier
HealthKit constants: https://developer.apple.com/documentation/healthkit/healthkit_constants
Bruno's answer is only half of the answer. For example, his standUnit variable is how he pulls the # of hours that the user has stood today. I tested it. Also, I made the assumption that it had to be pulled from within the scope of the summaries variable.
I have found another question on StackOverflow that might provide some clues. I think they managed to pull a value via a HKCategoryTypeIdentifier: Watch os 2.0 beta: access heart beat rate
Here's my attempted code as far as I have been able to get:
import UIKit
import HealthKit
import HealthKitUI
class ViewController: UIViewController {
let hkStoreOnVC : HKHealthStore = HKHealthStore()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
authorizeHealthKit()
hkTest()
hkTest2()
}
func authorizeHealthKit() { //-> Bool {
print("health kit authorize?")
let healthStore = HKHealthStore()
let objectTypes: Set<HKObjectType> = [
HKObjectType.activitySummaryType()
]
healthStore.requestAuthorization(toShare: nil, read: objectTypes) { (success, error) in
// Authorization request finished, hopefully the user allowed access!
print("health kit authorized")
}
}
func hkTest() {
print("health kit test.")
let calendar = Calendar.autoupdatingCurrent
var dateComponents = calendar.dateComponents(
[ .year, .month, .day ],
from: Date()
)
// This line is required to make the whole thing work
dateComponents.calendar = calendar
let predicate = HKQuery.predicateForActivitySummary(with: dateComponents)
//----------------------
let query = HKActivitySummaryQuery(predicate: predicate) { (query, summaries, error) in
print("query")
guard let summaries = summaries, summaries.count > 0
else {
print("no summaries")
return
}
// Handle data
for thisSummary in summaries {
// print("for each summary")
let standUnit = HKUnit.count()
let standHours = thisSummary.appleStandHours.doubleValue(for: standUnit)
print("stand hours \(standHours)")
}//end for
} //end query
}
func hkTest2() {
var isEnabled = true
print ("authorize health kit" )
if HKHealthStore.isHealthDataAvailable() {
let stepsCount = NSSet(objects: HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.stepCount ) )
for thisValue in stepsCount {
// thisValue.
print("thisValue: \(thisValue)")
}
print(" authorize HK - steps count \(stepsCount) ")
}
// Create the date components for the predicate
guard let calendar = NSCalendar(calendarIdentifier: NSCalendar.Identifier.gregorian) else {
fatalError("*** This should never fail. ***")
}
let endDate = NSDate()
guard let startDate = calendar.date(byAdding: .day, value: -7, to: endDate as Date, options: []) else {
fatalError("*** unable to calculate the start date ***")
}
let units: NSCalendar.Unit = [.day, .month, .year, .era]
var startDateComponents = calendar.components(units, from: startDate)
startDateComponents.calendar = calendar as Calendar
var endDateComponents = calendar.components(units, from: endDate as Date)
endDateComponents.calendar = calendar as Calendar
// Create the predicate for the query
let summariesWithinRange = HKQuery.predicate(forActivitySummariesBetweenStart: startDateComponents, end: endDateComponents)
// Build the query
let query = HKActivitySummaryQuery(predicate: summariesWithinRange) { (query, summaries, error) -> Void in
guard let activitySummaries = summaries else {
guard let queryError = error else {
fatalError("*** Did not return a valid error object. ***")
}
// Handle the error here...
return
}
for thisSummary in activitySummaries {
// print("for each summary")
let standUnit = HKUnit.count()
let standHours = thisSummary.appleStandHours.doubleValue(for: standUnit)
// let stoodThisHourMaybe = thisSummary.appleStandHours.categ //doubleValue(for: standUnit)
//\(thisSummary.description) //stand unit _\(standUnit)_
print("day#\(thisSummary.dateComponents(for: calendar as Calendar).day) stand hours \(standHours) ")
}//end for
// Do something with the summaries here...
for thisItem in activitySummaries {
//thisItem.appleStandHours
print("abc \( thisItem.appleStandHours ) " )
}//end for
}
// Run the query
let hkStore : HKHealthStore = HKHealthStore()
hkStore.execute(query)
//***
let aStandHour = HKCategoryType.categoryType(forIdentifier: .appleStandHour)
// This is the type you want updates on. It can be any health kit type, including heart rate.
// let distanceType = HKObjectType.quantityType(forIdentifier: HKQuantityTypeIdentifier.distanceWalkingRunning)
// Match samples with a start date after the workout start
// let predicate = .predicat //( , endDate: nil, options: .None)
// let theDate : Date =
let thepredicate = HKQuery.predicateForCategorySamples(with: .greaterThanOrEqualTo, value: 0) //.predicateForSamplesWithStartDate(startDate , endDate: nil, options: .None)
// predicate
// let predicate = . //(theDate , endDate: nil, options: .None)
let hka : HKQueryAnchor = HKQueryAnchor(fromValue: 0)
let sHourQuery = HKAnchoredObjectQuery(type: aStandHour!, predicate: thepredicate, anchor: hka, limit: 0, resultsHandler: { ( query, samples, deletedObjects, anchor, error) -> Void in
// Handle when the query first returns results
// TODO: do whatever you want with samples (note you are not on the main thread)
print("getting here A?")
// for thisSample in samples! {
// print("A smpLType \(thisSample.sampleType) thisSample \(thisSample)")
// }
})
// This is called each time a new value is entered into HealthKit (samples may be batched together for efficiency)
sHourQuery.updateHandler = { (query, samples, deletedObjects, anchor, error) -> Void in
// Handle update notifications after the query has initially run
// TODO: do whatever you want with samples (note you are not on the main thread)
print("getting here B?")
for thisSample in samples! {
print("B smpLType \(thisSample.sampleType) thisSample \(thisSample)")
}
}
// Start the query
self.hkStoreOnVC.execute(sHourQuery)
//***
}//end func
func myCompletionHandler(bTest: Bool ) {
print("my completion handler")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}//end viewController Class
Here's the code output - the log never prints to "getting here b?":
health kit authorize?
health kit test.
authorize health kit
health kit authorized
thisValue: HKQuantityTypeIdentifierStepCount
authorize HK - steps count {(
HKQuantityTypeIdentifierStepCount
)}
2017-11-04 19:18:30.100562-0500 watchapptest[25048:4695625] refreshPreferences: HangTracerEnabled: 0
2017-11-04 19:18:30.100600-0500 watchapptest[25048:4695625] refreshPreferences: HangTracerDuration: 500
2017-11-04 19:18:30.100615-0500 watchapptest[25048:4695625] refreshPreferences: ActivationLoggingEnabled: 0 ActivationLoggingTaskedOffByDA:0
getting here A?
day#Optional(28) stand hours 14.0
day#Optional(29) stand hours 14.0
day#Optional(30) stand hours 14.0
day#Optional(31) stand hours 14.0
day#Optional(1) stand hours 16.0
day#Optional(2) stand hours 13.0
day#Optional(3) stand hours 15.0
day#Optional(4) stand hours 13.0
abc 14 count
abc 14 count
abc 14 count
abc 14 count
abc 16 count
abc 13 count
abc 15 count
abc 13 count
I am new to HealthKit, so there probably is a nicer way to do this. But this seems to work for me. I check the actually standing minutes and call the completion handler with minutes > 0.
private let store = HKHealthStore()
func askPermission() {
let standType = HKQuantityType.quantityType(forIdentifier: .appleStandTime)!
store.requestAuthorization(toShare: [], read: [standType], completion: { (success, error) in
self.didStandThisHour { (didStand) in
print("Did stand this hour: \(didStand)")
}
})
}
func didStandThisHour(_ didStand: #escaping (Bool) -> ()) {
let store = HKHealthStore()
let calendar = Calendar.autoupdatingCurrent
let dateComponents = calendar.dateComponents([.year, .month, .day, .hour], from: Date())
let endDate = Date()
let startDate = calendar.date(from: dateComponents)!
let standTime = HKQuantityType.quantityType(forIdentifier: HKQuantityTypeIdentifier.appleStandTime)!
var interval = DateComponents()
interval.hour = 1
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: .strictStartDate)
let query = HKStatisticsCollectionQuery(quantityType: standTime, quantitySamplePredicate: predicate, options: [.cumulativeSum], anchorDate: startDate, intervalComponents:interval)
query.initialResultsHandler = { query, results, error in
guard error == nil, let myResults = results else {
fatalError("Something is wrong with HealthKit link")
}
myResults.enumerateStatistics(from: startDate, to: endDate, with: { (statistics, stop) in
guard let quantity = statistics.sumQuantity() else {
didStand(false)
return
}
let minutes = quantity.doubleValue(for: .minute())
didStand(minutes > 0)
})
}
store.execute(query)
}
Ok, if you want to retrieve today's activity ring info (including stand hours) you first request user authorization for the object type you want to retrieve:
let healthStore = HKHealthStore()
let objectTypes: Set<HKObjectType> = [
HKObjectType.activitySummaryType()
]
healthStore.requestAuthorization(toShare: nil, read: objectTypes) { (success, error) in
// Authorization request finished, hopefully the user allowed access!
}
Then you can use this predicate to retrieve today's date:
let calendar = Calendar.autoupdatingCurrent
var dateComponents = calendar.dateComponents(
[ .year, .month, .day ],
from: Date()
)
// This line is required to make the whole thing work
dateComponents.calendar = calendar
let predicate = HKQuery.predicateForActivitySummary(with: dateComponents)
Create a query...
let query = HKActivitySummaryQuery(predicate: predicate) { (query, summaries, error) in
guard let summaries = summaries, summaries.count > 0
else {
return
}
// Handle data
}
The data you'll receive is of type HKActivitySummary and you can retrieve, for example:
let sandUnit = HKUnit.count()
let standHours = summary.appleStandHours.doubleValue(for: standUnit)

For iOS healthkit how to save systolic and diastolic blood pressure values?

Here is code for saving blood pressure data in health kit
HKUnit *BPunit = [HKUnit millimeterOfMercuryUnit];
HKQuantity *BPSysQuantity = [HKQuantity quantityWithUnit:BPunit doubleValue:150.0];
HKQuantityType *BPSysType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodPressureSystolic];
HKQuantitySample *BPSysSample = [HKQuantitySample quantitySampleWithType:BPSysType quantity:BpsysQuantity startDate:now endDate:now];
[self.healthStore saveObject:BPSysSample withCompletion:^(BOOL success, NSError *error)
same way for diastolic also,
But how to save both combine as single entry in health app? Currently two diffrent entries are saved for systolic and diastolic blood pressure in health app.
- (void)saveBloodPressureIntoHealthStore:(double)Systolic Dysbp:(double)Diastolic {
HKUnit *BloodPressureUnit = [HKUnit millimeterOfMercuryUnit];
HKQuantity *SystolicQuantity = [HKQuantity quantityWithUnit:BloodPressureUnit doubleValue:Systolic];
HKQuantity *DiastolicQuantity = [HKQuantity quantityWithUnit:BloodPressureUnit doubleValue:Diastolic];
HKQuantityType *SystolicType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodPressureSystolic];
HKQuantityType *DiastolicType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierBloodPressureDiastolic];
NSDate *now = [NSDate date];
HKQuantitySample *SystolicSample = [HKQuantitySample quantitySampleWithType:SystolicType quantity:SystolicQuantity startDate:now endDate:now];
HKQuantitySample *DiastolicSample = [HKQuantitySample quantitySampleWithType:DiastolicType quantity:DiastolicQuantity startDate:now endDate:now];
NSSet *objects=[NSSet setWithObjects:SystolicSample,DiastolicSample, nil];
HKCorrelationType *bloodPressureType = [HKObjectType correlationTypeForIdentifier:
HKCorrelationTypeIdentifierBloodPressure];
HKCorrelation *BloodPressure = [HKCorrelation correlationWithType:bloodPressureType startDate:now endDate:now objects:objects];
[self.healthStore saveObject:BloodPressure withCompletion:^(BOOL success, NSError *error) {
if (!success) {
NSLog(#"An error occured saving the height sample %#. In your app, try to handle this gracefully. The error was: %#.", BloodPressure, error);
abort();
}
[_activity stopAnimating];
UIAlertView *savealert=[[UIAlertView alloc]initWithTitle:#"HealthDemo" message:#"Blood Pressure values has been saved to Health App" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[savealert show];
}];
}
In Swift 3:
func saveBloodPressure(systolic systolicValue: Double, diastolic diastolicValue: Double, completion completionBlock: #escaping (Bool, Error?) -> Void) {
let unit = HKUnit.millimeterOfMercury()
let systolicQuantity = HKQuantity(unit: unit, doubleValue: systolicValue)
let diastolicQuantity = HKQuantity(unit: unit, doubleValue: diastolicValue)
let systolicType = HKQuantityType.quantityType(forIdentifier: .bloodPressureSystolic)!
let diastolicType = HKQuantityType.quantityType(forIdentifier: .bloodPressureDiastolic)!
let nowDate = Date()
let systolicSample = HKQuantitySample(type: systolicType, quantity: systolicQuantity, start: nowDate, end: nowDate)
let diastolicSample = HKQuantitySample(type: diastolicType, quantity: diastolicQuantity, start: nowDate, end: nowDate)
let objects: Set<HKSample> = [systolicSample, diastolicSample]
let type = HKObjectType.correlationType(forIdentifier: .bloodPressure)!
let correlation = HKCorrelation(type: type, start: nowDate, end: nowDate, objects: objects)
self.healthKitStore.save(correlation) { (success, error) -> Void in
if !success {
print("An error occured saving the Blood pressure sample \(systolicSample). In your app, try to handle this gracefully. The error was: \(error).")
}
completionBlock(success, error)
}
}
Check out HKCorrelation. A correlation is a set of related objects and is designed to represent things like blood pressure readings and food. You can save create and save correlations just like samples and you can query for correlations using HKCorrelationQuery.
Swift : iOS : Save Blood Pressure:
private func saveBloodPressureIntoHealthStore(bloodPressureValueSystolic:Double
,bloodPressureValueDiastolic:Double) -> Void {
// Save the user's blood pressure into HealthKit.
let bloodPressureUnit: HKUnit = HKUnit.millimeterOfMercuryUnit()
let bloodPressureSystolicQuantity: HKQuantity = HKQuantity(unit: bloodPressureUnit, doubleValue: bloodPressureValueSystolic)
let bloodPressureDiastolicQuantity: HKQuantity = HKQuantity(unit: bloodPressureUnit, doubleValue: bloodPressureValueDiastolic)
let bloodPressureSystolicType: HKQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBloodPressureSystolic)
let bloodPressureDiastolicType: HKQuantityType = HKQuantityType.quantityTypeForIdentifier(HKQuantityTypeIdentifierBloodPressureDiastolic)
let nowDate: NSDate = NSDate()
let bloodPressureSystolicSample: HKQuantitySample = HKQuantitySample(type: bloodPressureSystolicType
, quantity: bloodPressureSystolicQuantity, startDate: nowDate, endDate: nowDate)
let bloodPressureDiastolicSample: HKQuantitySample = HKQuantitySample(type: bloodPressureDiastolicType
, quantity: bloodPressureDiastolicQuantity, startDate: nowDate, endDate: nowDate)
let completion: ((Bool, NSError!) -> Void) = {
(success, error) -> Void in
if !success {
println("An error occured saving the Blood pressure sample \(bloodPressureSystolicSample). In your app, try to handle this gracefully. The error was: \(error).")
abort()
}
}// end completion
var objects : NSSet = NSSet(objects: bloodPressureSystolicSample,bloodPressureDiastolicSample)
var bloodPressureType: HKCorrelationType = HKObjectType.correlationTypeForIdentifier(HKCorrelationTypeIdentifierBloodPressure)
var bloodPressureCorrelation : HKCorrelation = HKCorrelation(type: bloodPressureType, startDate: nowDate
, endDate: nowDate, objects: objects)
self.healthStore!.saveObject(bloodPressureCorrelation, withCompletion: completion)
}// end saveBloodPressureIntoHealthStore
Xamarin.iOS solution
public void SaveBloodPressure(DateTime date, double systolic, double diastolic, double beatsPerMinute)
{
using (var healthKitStore = new HKHealthStore())
{
var heartRateUnitType = HKUnit.MillimeterOfMercury;
var diastolicQuantity = HKQuantity.FromQuantity(heartRateUnitType, diastolic);
var diastolicQuantityType = HKQuantityType.GetQuantityType(HKQuantityTypeIdentifierKey.BloodPressureDiastolic);
var diastolicSample = HKQuantitySample.FromType(diastolicQuantityType, diastolicQuantity, date.ToUniversalTime().ToNSDate(), date.ToUniversalTime().ToNSDate(), new HKMetadata());
var systolicQuantity = HKQuantity.FromQuantity(heartRateUnitType, systolic);
var systolicQuantityType = HKQuantityType.GetQuantityType(HKQuantityTypeIdentifierKey.BloodPressureSystolic);
var systolicSample = HKQuantitySample.FromType(systolicQuantityType, systolicQuantity, date.ToUniversalTime().ToNSDate(), date.ToUniversalTime().ToNSDate(), new HKMetadata());
var objects = new NSSet(systolicSample, diastolicSample);
var bloodPressureType = HKCorrelationType.GetCorrelationType(HKCorrelationTypeKey.IdentifierBloodPressure);
var bloodPressure = HKCorrelation.Create(bloodPressureType, date.ToUniversalTime().ToNSDate(), date.ToUniversalTime().ToNSDate(), objects);
try
{
healthKitStore.SaveObject(bloodPressure, (success, error) =>
{
//action to take on success/failure
});
}
catch (Exception)
{
//handle exception
}
try
{
var beatsPerMinuteUnits = HKUnit.Count.UnitDividedBy(HKUnit.Minute);
var beatsPerMinuteQuantity = HKQuantity.FromQuantity(beatsPerMinuteUnits, beatsPerMinute);
var heartRateQuantityType = HKQuantityType.GetQuantityType(HKQuantityTypeIdentifierKey.HeartRate);
var heartRateSample = HKQuantitySample.FromType(heartRateQuantityType, beatsPerMinuteQuantity, date.ToUniversalTime().ToNSDate(), date.ToUniversalTime().ToNSDate(), new HKMetadata());
healthKitStore.SaveObject(heartRateSample, (success, error) =>
{
//handle success / failure
});
}
catch (Exception)
{
//handle exception
}
}
}