What's new in HealthKit

RSS for tag

Discuss the WWDC22 Session What's new in HealthKit

Posts under wwdc2022-10005 tag

9 Posts

Post

Replies

Boosts

Views

Activity

How can I read and display workout data similar to Apple Fitness?
I'm looking to display the workouts performed similar to what Apple Fitness displays. However, I want to get traditional strength training and functional strength training workouts particularly. I would also like to get the number of workouts performed within the week. I'm having issues reading the data and displaying it. Below is the code I'm using. I'm omitting the authorization method because I have that with other health variables I'm getting. Also, when I try to get the workoutActivity type to display, nothing is showing up. I've looked over apple's healthkit documentation but getting a big confused/lost as a beginner, particularly with the workout data. I've attached pictures as a reference on what I would like to accomplish var selectedWorkoutQuery: HKQuery? @Published var muscleStrength: [HKWorkout] = [HKWorkout]() func getStrengthTrainingWorkouts() { let date = Date() let startDate = Calendar.current.dateInterval(of: .weekOfYear, for: date)?.start let datePredicate = HKQuery.predicateForSamples(withStart: startDate, end: nil, options: .strictStartDate) let traditionalStrengthTrainingPredicate = HKQuery.predicateForWorkouts(with: .traditionalStrengthTraining) let functionalStrengthTrainingPredicate = HKQuery.predicateForWorkouts(with: .functionalStrengthTraining) let strengthCompound = NSCompoundPredicate(andPredicateWithSubpredicates: [datePredicate, traditionalStrengthTrainingPredicate, functionalStrengthTrainingPredicate]) let selectedWorkoutQuery = HKSampleQuery(sampleType: HKWorkoutType.workoutType(), predicate: strengthCompound, limit: HKObjectQueryNoLimit, sortDescriptors: nil) { strengthQuery, samples, error in guard let samples = samples else { fatalError("An error has occured \(error?.localizedDescription)") } DispatchQueue.main.async { if let workouts = samples as? [HKWorkout] { for workout in workouts { self.muscleStrength.append(workout) } } } } self.healthStore?.execute(selectedWorkoutQuery) } Here is the view I would like to display the count and workouts but nothing is showing struct MuscleView: View { @ObservedObject var healthStoreVM: HealthStoreViewModel var body: some View { List(healthStoreVM.muscleStrength, id: \.self) { workout in Text("\(workout.workoutActivityType.rawValue)") } } }
1
0
1.5k
Apr ’23
Issues with healthkit's update handlers
I can't seem to wrap my head around with long running queries in HealthKit when it comes dealing with the update handlers. I ask because from my end when I upload my code to the physical device, my data is reloaded and appending to my array which is adding additional data to the screen. From my understanding the updateHandlers monitors for new data/values in the background to update the value in a new view. I'm trying to mimic the Apple Fitness/Health app where the value updates and displays it to the user without having to close the app or switch views. I tried to be concise with my code mainly to get an idea of the updateHandler. I tried stopping the query and .onDisappear modifier but the .onDisappear wouldn't update the values unless I force closed the app and opened it again. //Properties within my view model for resting HR. var restingHRquery: HKStatisticsCollectionQuery? @Published var restingHR: [RestingHeartRate] = [RestingHeartRate]() func calculateRestingHRData() { let restingHRpredicate = HKQuery.predicateForSamples(withStart: oneWeekAgo, end: nil, options: .strictStartDate) restingHRquery = HKStatisticsCollectionQuery(quantityType: restingHeartRateType, quantitySamplePredicate: restingHRpredicate, options: .discreteAverage, anchorDate: anchorDate, intervalComponents: daily) restingHRquery!.initialResultsHandler = { restingQuery, statisticsCollection, error in //Handle errors here if let error = error as? HKError { switch (error.code) { case .errorHealthDataUnavailable: return case .errorNoData: return default: return } } guard let statisticsCollection = statisticsCollection else { return} //Calculating resting HR statisticsCollection.enumerateStatistics(from: self.startDate, to: self.date) { statistics, stop in if let restHRquantity = statistics.averageQuantity() { let hrdate = statistics.startDate //HR Units let hrUnit = HKUnit(from: "count/min") let restHRvalue = restHRquantity.doubleValue(for: hrUnit) let restHR = RestingHeartRate(restingValue: Int(restHRvalue), date: hrdate) DispatchQueue.main.async { self.restingHR.append(restHR) } } } } restingHRquery!.statisticsUpdateHandler = { restingQuery, statistics, statisticsCollection, error in //Handle errors here if let error = error as? HKError { switch (error.code) { case .errorHealthDataUnavailable: return case .errorNoData: return default: return } } guard let statisticsCollection = statisticsCollection else { return} //Calculating resting HR statisticsCollection.enumerateStatistics(from: self.startDate, to: self.date) { statistics, stop in if let restHRquantity = statistics.averageQuantity() { let hrdate = statistics.startDate //HR Units let hrUnit = HKUnit(from: "count/min") let restHRvalue = restHRquantity.doubleValue(for: hrUnit) let restHR = RestingHeartRate(restingValue: Int(restHRvalue), date: hrdate) DispatchQueue.main.async { self.restingHR.append(restHR) } } } } guard let restingHRquery = self.restingHRquery else { return } self.healthStore?.execute(restingHRquery) } My chart always being updated which causes it to reload my list and draw new data on the charts which makes the line go crazy. I'm using the EnvironmentObject because it's a subview. I'm just getting straight to the chart view struct OneWeekRestHRChartView: View { @EnvironmentObject var healthStoreVM: HealthStoreViewModel var body: some View { VStack(alignment: .leading, spacing: 10) { Text("Average: \(healthStoreVM.averageRestHR) bpm") .font(.headline) Chart { ForEach(healthStoreVM.restingHR.reversed(), id: \.date) { restHrData in LineMark(x: .value("day", restHrData.date, unit: .day), y: .value("RHR", restHrData.restingValue) ) .interpolationMethod(.catmullRom) .foregroundStyle(.red) .symbol() { Circle() .fill(.red) .frame(width: 15) } } } .frame(height: 200) .chartYScale(domain: 30...80) .chartXAxis { AxisMarks(values: .stride(by: .day)) { AxisGridLine() AxisValueLabel(format: .dateTime.day().month(), centered: true) } } } .padding(.horizontal) .navigationTitle("Resting Heart Rate") List{ ForEach(healthStoreVM.restingHR.reversed(), id: \.date) { restHR in DataListView(imageText: "heart.fill", imageColor: .red, valueText: "\(restHR.restingValue) bpm", date: restHR.date) } } .listStyle(.inset) } } Could this just be a SwiftUI chart issue?
0
0
776
Apr ’23
assuming human error on source code for "What's new in HealthKit" session
This is the copy of source code one could see on What's new in Health Kit Session: // predicate for sleep samples let remSleepStagePredicate = HKCategoryValueSleepAnalysis.predicateForSamples(.equalTo, value: .asleepREM) // create query with the designated sleepStagePredicate let queryPredicate = HKSamplePredicate.sample(type: HKCategoryType(.sleepAnalysis), predicate: remSleepStagePredicate) // Sleep Query let sleepQuery = HKSampleQueryDescriptor(predicates: [queryPredicate], sortDescriptors: []) // Run the query let sleepSamples = try async sleepQuery.result(for: healthStore) I tried to take a snaphot of the session itself, but for some reason I could not submit it with the file attached so I provided the code above. I am wondering that shouldn't it be try await, not try async on the last line of the source code? so the last line should be the code below: let sleepSamples = try await sleepQuery.result(for: healthStore) Am I mistaken, or is it a human error?
2
0
1.2k
Nov ’22
New running metrics (runningPower, runningSpeed) not working in watchOS 9 beta 2
I'm using watchOS 9 beta 2 and I'm not getting the new running metrics in my workout app. Using HKLiveWorkoutDataSource attached to a HKWorkoutBuilder ActivityType is running Tried enabling the collection of the new metrics According to Jorge M in the WWDC labs: "Yes, the new running metrics are also available for 3rd party applications. If you are using an HKLiveWorkoutDataSource attached to a HKWorkoutBuilder in your application, the new metrics would be collected by default." The Health app does not show any Related Samples for these types. Am I doing something wrong or are they not available yet to 3rd party workouts? I do see them for the Apple Workout app.
2
2
1.8k
Sep ’22
Sort workouts using the HKSampleQueryDescriptor
Is it possible to set TotalDistance for the sorts of HKSampleQueryDescriptor? In HKSampleQuery, I can set TotalDistance as follows. let sort = NSSortDescriptor(key: HKWorkoutSortIdentifierTotalDistance, ascending: false) let type = HKWorkoutType.workoutType() let query = HKSampleQuery(sampleType: type, predicate: nil, limit: 0, sortDescriptors: [sort] ){ (query, results, error) -> Void in } I want to create a SortDescriptor for HKSampleQueryDescriptor. When I set HKWorkout.totalDistance to parameter in SortDescriptor, the compile error occurred. let sort = SortDescriptor(\HKWorkout.totalDistance, order: .forward) // Error: "No exact matches in call to initializer" I know that HKWorkout.totalDistance is deprecated. Isn't it recommended to set TotalDistance to sort? I'm expecting that on iOS 16, I can get my workouts in heart rate order, is this a mistake?
0
0
819
Jun ’22
HKStatisticsCollectionQueryDescriptor document example is not executed.
let stepType = HKQuantityType(.stepCount)         let stepsThisWeek = HKSamplePredicate.quantitySample(type: stepType, predicate: thisWeek)         let yesterday = calendar.date(byAdding: .day, value: -1, to: calendar.startOfDay(for: now))         let every5 = DateComponents(minute:5)         let healthTypes = Set([             HKCategoryType.categoryType(forIdentifier: .handwashingEvent)!         ])         let sumOfStepsQuery = HKStatisticsCollectionQueryDescriptor(             predicate: stepsThisWeek,             options: .cumulativeSum,             anchorDate: endDate,             intervalComponents: every5)         do {             let updateQueue = sumOfStepsQuery.results(for: store)             // Wait for the initial results and updates.             updateQueue = Task {                 for try await results in updateQueue {                     // Use the statistics collection here.                 }             }                      } catch {             //handle error             print(error)         }
0
0
1.1k
Jun ’22
How can I read and display workout data similar to Apple Fitness?
I'm looking to display the workouts performed similar to what Apple Fitness displays. However, I want to get traditional strength training and functional strength training workouts particularly. I would also like to get the number of workouts performed within the week. I'm having issues reading the data and displaying it. Below is the code I'm using. I'm omitting the authorization method because I have that with other health variables I'm getting. Also, when I try to get the workoutActivity type to display, nothing is showing up. I've looked over apple's healthkit documentation but getting a big confused/lost as a beginner, particularly with the workout data. I've attached pictures as a reference on what I would like to accomplish var selectedWorkoutQuery: HKQuery? @Published var muscleStrength: [HKWorkout] = [HKWorkout]() func getStrengthTrainingWorkouts() { let date = Date() let startDate = Calendar.current.dateInterval(of: .weekOfYear, for: date)?.start let datePredicate = HKQuery.predicateForSamples(withStart: startDate, end: nil, options: .strictStartDate) let traditionalStrengthTrainingPredicate = HKQuery.predicateForWorkouts(with: .traditionalStrengthTraining) let functionalStrengthTrainingPredicate = HKQuery.predicateForWorkouts(with: .functionalStrengthTraining) let strengthCompound = NSCompoundPredicate(andPredicateWithSubpredicates: [datePredicate, traditionalStrengthTrainingPredicate, functionalStrengthTrainingPredicate]) let selectedWorkoutQuery = HKSampleQuery(sampleType: HKWorkoutType.workoutType(), predicate: strengthCompound, limit: HKObjectQueryNoLimit, sortDescriptors: nil) { strengthQuery, samples, error in guard let samples = samples else { fatalError("An error has occured \(error?.localizedDescription)") } DispatchQueue.main.async { if let workouts = samples as? [HKWorkout] { for workout in workouts { self.muscleStrength.append(workout) } } } } self.healthStore?.execute(selectedWorkoutQuery) } Here is the view I would like to display the count and workouts but nothing is showing struct MuscleView: View { @ObservedObject var healthStoreVM: HealthStoreViewModel var body: some View { List(healthStoreVM.muscleStrength, id: \.self) { workout in Text("\(workout.workoutActivityType.rawValue)") } } }
Replies
1
Boosts
0
Views
1.5k
Activity
Apr ’23
Issues with healthkit's update handlers
I can't seem to wrap my head around with long running queries in HealthKit when it comes dealing with the update handlers. I ask because from my end when I upload my code to the physical device, my data is reloaded and appending to my array which is adding additional data to the screen. From my understanding the updateHandlers monitors for new data/values in the background to update the value in a new view. I'm trying to mimic the Apple Fitness/Health app where the value updates and displays it to the user without having to close the app or switch views. I tried to be concise with my code mainly to get an idea of the updateHandler. I tried stopping the query and .onDisappear modifier but the .onDisappear wouldn't update the values unless I force closed the app and opened it again. //Properties within my view model for resting HR. var restingHRquery: HKStatisticsCollectionQuery? @Published var restingHR: [RestingHeartRate] = [RestingHeartRate]() func calculateRestingHRData() { let restingHRpredicate = HKQuery.predicateForSamples(withStart: oneWeekAgo, end: nil, options: .strictStartDate) restingHRquery = HKStatisticsCollectionQuery(quantityType: restingHeartRateType, quantitySamplePredicate: restingHRpredicate, options: .discreteAverage, anchorDate: anchorDate, intervalComponents: daily) restingHRquery!.initialResultsHandler = { restingQuery, statisticsCollection, error in //Handle errors here if let error = error as? HKError { switch (error.code) { case .errorHealthDataUnavailable: return case .errorNoData: return default: return } } guard let statisticsCollection = statisticsCollection else { return} //Calculating resting HR statisticsCollection.enumerateStatistics(from: self.startDate, to: self.date) { statistics, stop in if let restHRquantity = statistics.averageQuantity() { let hrdate = statistics.startDate //HR Units let hrUnit = HKUnit(from: "count/min") let restHRvalue = restHRquantity.doubleValue(for: hrUnit) let restHR = RestingHeartRate(restingValue: Int(restHRvalue), date: hrdate) DispatchQueue.main.async { self.restingHR.append(restHR) } } } } restingHRquery!.statisticsUpdateHandler = { restingQuery, statistics, statisticsCollection, error in //Handle errors here if let error = error as? HKError { switch (error.code) { case .errorHealthDataUnavailable: return case .errorNoData: return default: return } } guard let statisticsCollection = statisticsCollection else { return} //Calculating resting HR statisticsCollection.enumerateStatistics(from: self.startDate, to: self.date) { statistics, stop in if let restHRquantity = statistics.averageQuantity() { let hrdate = statistics.startDate //HR Units let hrUnit = HKUnit(from: "count/min") let restHRvalue = restHRquantity.doubleValue(for: hrUnit) let restHR = RestingHeartRate(restingValue: Int(restHRvalue), date: hrdate) DispatchQueue.main.async { self.restingHR.append(restHR) } } } } guard let restingHRquery = self.restingHRquery else { return } self.healthStore?.execute(restingHRquery) } My chart always being updated which causes it to reload my list and draw new data on the charts which makes the line go crazy. I'm using the EnvironmentObject because it's a subview. I'm just getting straight to the chart view struct OneWeekRestHRChartView: View { @EnvironmentObject var healthStoreVM: HealthStoreViewModel var body: some View { VStack(alignment: .leading, spacing: 10) { Text("Average: \(healthStoreVM.averageRestHR) bpm") .font(.headline) Chart { ForEach(healthStoreVM.restingHR.reversed(), id: \.date) { restHrData in LineMark(x: .value("day", restHrData.date, unit: .day), y: .value("RHR", restHrData.restingValue) ) .interpolationMethod(.catmullRom) .foregroundStyle(.red) .symbol() { Circle() .fill(.red) .frame(width: 15) } } } .frame(height: 200) .chartYScale(domain: 30...80) .chartXAxis { AxisMarks(values: .stride(by: .day)) { AxisGridLine() AxisValueLabel(format: .dateTime.day().month(), centered: true) } } } .padding(.horizontal) .navigationTitle("Resting Heart Rate") List{ ForEach(healthStoreVM.restingHR.reversed(), id: \.date) { restHR in DataListView(imageText: "heart.fill", imageColor: .red, valueText: "\(restHR.restingValue) bpm", date: restHR.date) } } .listStyle(.inset) } } Could this just be a SwiftUI chart issue?
Replies
0
Boosts
0
Views
776
Activity
Apr ’23
HKQuantityTypeIdentifier Cadence
Hi. is there a explicit HKQuantityTypeIdentifier for the new Cadence value in iOS 16. I only can find in the documentation HKQuantityTypeIdentifier runningPower runningSpeed runningStrideLength runningVerticalOscillation runningGroundContactTime But nothing like runningCadence???
Replies
3
Boosts
0
Views
1.6k
Activity
Mar ’23
assuming human error on source code for "What's new in HealthKit" session
This is the copy of source code one could see on What's new in Health Kit Session: // predicate for sleep samples let remSleepStagePredicate = HKCategoryValueSleepAnalysis.predicateForSamples(.equalTo, value: .asleepREM) // create query with the designated sleepStagePredicate let queryPredicate = HKSamplePredicate.sample(type: HKCategoryType(.sleepAnalysis), predicate: remSleepStagePredicate) // Sleep Query let sleepQuery = HKSampleQueryDescriptor(predicates: [queryPredicate], sortDescriptors: []) // Run the query let sleepSamples = try async sleepQuery.result(for: healthStore) I tried to take a snaphot of the session itself, but for some reason I could not submit it with the file attached so I provided the code above. I am wondering that shouldn't it be try await, not try async on the last line of the source code? so the last line should be the code below: let sleepSamples = try await sleepQuery.result(for: healthStore) Am I mistaken, or is it a human error?
Replies
2
Boosts
0
Views
1.2k
Activity
Nov ’22
New running metrics (runningPower, runningSpeed) not working in watchOS 9 beta 2
I'm using watchOS 9 beta 2 and I'm not getting the new running metrics in my workout app. Using HKLiveWorkoutDataSource attached to a HKWorkoutBuilder ActivityType is running Tried enabling the collection of the new metrics According to Jorge M in the WWDC labs: "Yes, the new running metrics are also available for 3rd party applications. If you are using an HKLiveWorkoutDataSource attached to a HKWorkoutBuilder in your application, the new metrics would be collected by default." The Health app does not show any Related Samples for these types. Am I doing something wrong or are they not available yet to 3rd party workouts? I do see them for the Apple Workout app.
Replies
2
Boosts
2
Views
1.8k
Activity
Sep ’22
Will AFib History be an open data source?
Will developers be able to access the AFib History feature coming to WatchOS 9? I work as an Epic Analyst for a local hospital in the digital health department and one of our programs uses the Apple Watch for AFib detection and I just wanted to make sure we would be able to access that info (with permission of course) through our own app.
Replies
2
Boosts
0
Views
1.2k
Activity
Aug ’22
Sort workouts using the HKSampleQueryDescriptor
Is it possible to set TotalDistance for the sorts of HKSampleQueryDescriptor? In HKSampleQuery, I can set TotalDistance as follows. let sort = NSSortDescriptor(key: HKWorkoutSortIdentifierTotalDistance, ascending: false) let type = HKWorkoutType.workoutType() let query = HKSampleQuery(sampleType: type, predicate: nil, limit: 0, sortDescriptors: [sort] ){ (query, results, error) -> Void in } I want to create a SortDescriptor for HKSampleQueryDescriptor. When I set HKWorkout.totalDistance to parameter in SortDescriptor, the compile error occurred. let sort = SortDescriptor(\HKWorkout.totalDistance, order: .forward) // Error: "No exact matches in call to initializer" I know that HKWorkout.totalDistance is deprecated. Isn't it recommended to set TotalDistance to sort? I'm expecting that on iOS 16, I can get my workouts in heart rate order, is this a mistake?
Replies
0
Boosts
0
Views
819
Activity
Jun ’22
HKStatisticsCollectionQueryDescriptor document example is not executed.
let stepType = HKQuantityType(.stepCount)         let stepsThisWeek = HKSamplePredicate.quantitySample(type: stepType, predicate: thisWeek)         let yesterday = calendar.date(byAdding: .day, value: -1, to: calendar.startOfDay(for: now))         let every5 = DateComponents(minute:5)         let healthTypes = Set([             HKCategoryType.categoryType(forIdentifier: .handwashingEvent)!         ])         let sumOfStepsQuery = HKStatisticsCollectionQueryDescriptor(             predicate: stepsThisWeek,             options: .cumulativeSum,             anchorDate: endDate,             intervalComponents: every5)         do {             let updateQueue = sumOfStepsQuery.results(for: store)             // Wait for the initial results and updates.             updateQueue = Task {                 for try await results in updateQueue {                     // Use the statistics collection here.                 }             }                      } catch {             //handle error             print(error)         }
Replies
0
Boosts
0
Views
1.1k
Activity
Jun ’22
can I use HKStatisticsCollectionQueryDescriptor to HKCategoryType
I want to query to washing event. but washing hand is HKCategoryType so I can't use HKStatiticsCollectionQueryDescriptor because it only accept HKQuantitySample. is there a way that I can use it ?
Replies
0
Boosts
0
Views
970
Activity
Jun ’22