Hi!
I am using the HKAnchoredObjectQuery to first get a snapshot of the initial results, and then trigger an updateHandler.
I need to handle the initial results and the updates separately, which is why I implemented two completions.
When I test the code, it works for a while. New and deleted samples trigger the updateHandler. However, after a while there appears an error:
[connection] nw_read_request_report [C2] Receive failed with error "Software caused connection abort"
Followingly, the updateHandler will stop getting triggered when I add updates in Apple health. Anyone have experience with this?
func getMostRecentSample(for sampleType: HKSampleType,
anchorKey: String,
completion: @escaping (HKQuantitySample?, Error?) -> Swift.Void,
updateHandler: @escaping (HKQuantitySample, Error?) -> Swift.Void) {
// If it is the first initialization, anchor is passed as nil
var anchor: HKQueryAnchor? = nil
// Check for previous saved anchor in userdefaults
if UserDefaults.standard.object(forKey: anchorKey) != nil {
let data = UserDefaults.standard.object(forKey: anchorKey) as! Data
do {
guard let newAnchor = try NSKeyedUnarchiver.unarchivedObject(ofClass: HKQueryAnchor.self, from: data) else {
print("Could not parse anchor to HKQueryAnchor type")
return
}
anchor = newAnchor
} catch {
print("Error retreiving anchor from UserDefaults")
}
}
let query = HKAnchoredObjectQuery(type: sampleType,
predicate: nil,
anchor: anchor,
limit: HKObjectQueryNoLimit
) { (query, samplesOrNil, _, newAnchor, errorOrNil) in
guard let samples = samplesOrNil as? [HKQuantitySample] else {
fatalError("*** An error occurred during the initial query: \(errorOrNil!.localizedDescription) ***")
}
if let anchor = newAnchor {
do {
let data = try NSKeyedArchiver.archivedData(withRootObject: anchor as Any, requiringSecureCoding: false)
UserDefaults.standard.set(data, forKey: anchorKey)
} catch {
print("Error retreiving anchor from UserDefaults")
}
}
completion(samples.last, nil)
}
// Setting up long-running query
query.updateHandler = { (query, samplesOrNil, _, newAnchor, errorOrNil) in
guard let samples = samplesOrNil as? [HKQuantitySample] else {
fatalError("*** An error occurred during an update: \(errorOrNil!.localizedDescription) ***")
}
if let anchor = newAnchor {
do {
let data = try NSKeyedArchiver.archivedData(withRootObject: anchor as Any, requiringSecureCoding: false)
UserDefaults.standard.set(data, forKey: anchorKey)
} catch {
print("Error retreiving anchor from UserDefaults")
}
}
if let sample = samples.last {
updateHandler(sample, nil)
}
}
self.healthStore.execute(query)
}
Use HealthKit to enable your iOS and watchOS apps to work with the Apple Health app.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Created
I'm trying to hook into the new workoutEffort score supported in iOS 18, I am collecting this information from users when they submit their workout and trying to add a sample to the HKWorkout in the same manner as I've been adding other samples like bodyweight, calories burned, etc.
I'm receiving the error:
HKWorkout: Sample of type HKQuantityTypeIdentifierWorkoutEffortScore must be related to a workout
I tried adding the samples using HKWorkoutBuilder.add([samples]) as which has been working perfectly for calories burned & bodyweight, but I am receiving the above error for workoutEffortScore
As a second approach, I tried adding the sample after I called finishWorkout on the HKWorkoutBuilder and received back the HKWorkout object using HKHealthStore.add([samples], to: HKWorkout) and am still receiving the same error!
I don't know otherwise how to relate a sample to a workout, I thought those were the APIs to do so? I'm using Xcode 16.0 RC (16A242) and testing on an iOS 16 Pro simulator
I have FB12696743 open since July 21, 2023 and this happened again today.
I get home at approx 10 mins after the hour, walk appox 50 ft across my yard, up 5 steps into my house, let the dog out and pace on my deck watching the dog, go back in the house walk around the kitchen while preparing dinner. A total of about 200 ft. I sit down about 35 past the hour and start to eat and at 10 mins to the next our and I get the reminder to stand.
On the other side I wake up at 5 mins to hour. Walk 8 steps to the bathroom and successfully achieve the stand for that hour.
WHY!?!?!? 😁🤣
We are seeing an issue where sending data using the asynchronous method HKWorkoutSession.sendToRemoteWorkoutSession(data: Data) will never return in some cases (no success nor failure).
This issue is happening for roughly 5% of Workouts started and will stay broken for the whole workout. The other 95% of the workouts, the connection works flawlessly. This happens on both watchOS 10 and 11, and with phones running iOS 17 or 18. The issue is quite random and not reproducible.
Our app has thousands of workouts a day that use the workout session workout data send, with constant messages being send every few seconds.
In some of those 5% cases the "sendToRemoteWorkoutSession" will throw way later, like 30+ minutes later, if the watch app is awake long enough to capture a log of a failure.
Our code uses the same flow as in the sample project:
https://developer.apple.com/documentation/healthkit/workouts_and_activity_rings/building_a_multidevice_workout_app
Here is some sample code, which is pretty simple.
Setup code:
let workoutSession = try HKWorkoutSession(healthStore: healthStore, configuration: configuration)
workoutSession.delegate = self
activeWorkoutSession?.startMirroringToCompanionDevice { success, error in
print("Mirroring started on companion device: \(success), error: \(error)")
}
workoutSession?.prepare()
then later we send data using the workout session:
do {
print("Will send data")
try await workoutSession.sendToRemoteWorkoutSession(data: data)
print("Successfully sent data") // This nor the error may be called after waiting extensive amounts of time
} catch {
print("Failed to send data, error: \(error)") // This nor the success may be called after waiting extensive amounts of time
}
So far, the only fix is to restart the phone and watch at the same time, which is not a great user experience.
Is anyone else seeing this issue? or know how to fix this issue?
Topic:
App & System Services
SubTopic:
Health & Fitness
Tags:
Watch Connectivity
Health and Fitness
watchOS
WorkoutKit
For a given date, there are discrepancies between the step counts obtained from HealthKit and those displayed in the Health app. Is it possible for such discrepancies to occur even if step counts are not manually entered and multiple devices are not being used?
We have working code to fetch step data from HealthKit after requesting the necessary permissions. However, we’ve encountered an issue specific to one device, the iPhone 16 Pro Max. When querying the data, we do not receive a response, and the code enters an infinite loading state without completing the request.
The user who is facing this issue has tried logging in on another device, and it works fine. On the problematic device (iPhone 16 Pro Max), the request does not complete.
For reference, I’ve included the code below. Resolving this issue is crucial, so we would appreciate any guidance on what steps we can take to troubleshoot or resolve the problem on this specific device.
Please note that the device has granted permission to access HealthKit data.
static let healthStore = HKHealthStore()
static func limitReadFromHealthKitBetweenDates(fromDate: Date, toDate: Date = Date(), completion: @escaping ([HKStatistics]) -> Void) {
guard let stepsQuantityType = HKQuantityType.quantityType(forIdentifier: .stepCount) else { return }
let ignoreUserEntered = HKQuery.predicateForObjects(withMetadataKey: HKMetadataKeyWasUserEntered, operatorType: .notEqualTo, value: true)
let now = toDate
var interval = DateComponents()
interval.day = 1
var calendar = Calendar.current
calendar.locale = Locale(identifier: "en_US_POSIX")
var anchorComponents = calendar.dateComponents([.day, .month, .year], from: now)
anchorComponents.hour = 0
let anchorDate = calendar.date(from: anchorComponents) ?? Date()
let query = HKStatisticsCollectionQuery(quantityType: stepsQuantityType,
quantitySamplePredicate: ignoreUserEntered,
options: [.cumulativeSum],
anchorDate: anchorDate,
intervalComponents: interval)
query.initialResultsHandler = { _, results, error in
guard let results = results else {
print("Error returned from resultHandler: \(String(describing: error?.localizedDescription))")
return
}
print(results)
var statisticsArray: [HKStatistics] = []
results.enumerateStatistics(from: fromDate, to: now) { statistics, _ in
statisticsArray.append(statistics)
if statistics.endDate.getddmmyyyyslashGMT == now.getddmmyyyyslashGMT {
completion(statisticsArray)
}
}
}
healthStore.execute(query)
}
Please note that the code works on all devices except the problematic one. Could you please guide me on the next steps to resolve this issue?
Topic:
App & System Services
SubTopic:
Health & Fitness
Tags:
iOS
iPhone
Health and Fitness
HealthKit
We currently use the HKCategoryValueMenstrualFlow enum to determine the type of menstrual flow: light, medium, etc. a user is having. We also use this enum in determining if it's an actual period day.
The Problem
I see HKCategoryValueMenstrualFlow was recently deprecated but has not been replaced by another data type.
Are there plans to replace/update it with another data type?
When or at what point in the future will this deprecation cause a problem in my code?
Hi everyone,
I’m developing a health-related mobile app and considering using EAS Update to deliver over-the-air (OTA) updates for JavaScript code and assets. Before implementing this, I want to ensure that this approach complies with Apple App Store policies, especially given the sensitivity of health-related apps.
Here are my concerns:
Does using EAS Update (OTA) align with Apple’s guidelines regarding app updates and dynamic behavior changes?
Are there specific rules or restrictions for health apps using OTA updates that I should be cautious of?
Could this approach be flagged as violating Apple’s policies on app integrity, especially those requiring updates to go through the App Store review process?
I’d greatly appreciate any insights, advice, or references to Apple’s official documentation regarding OTA updates for apps distributed through the App Store.
Thanks in advance for your help!
Good afternoon,
I am working on a workout tracking app. So far everything is working as expected. However, I note that when my workout saves and is visible within the Fitness App, the workout duration is displayed rather than the kCal burned.
What changes are required to be made in order for this to display the kCal in the list of workouts in Fitness rather than duration?
For reference https://developer.apple.com/videos/play/wwdc2021/10009 this was my reference source for workout functionality.
I have a workout app which I am testing on device currently via TestFlight.
The generated workout (tennis and indoor) shows in the fitness app with correct HR and duration.
However, when I go to my Strava app, it does not show in the list of workouts for importing. (note, activities tracked using the regular tennis mode on the Apple Watch show fine)
I have also concurrently reached out to Strava support to see if there's anything they can offer support for.
However, does anybody here have any knowledge/experience of the requirement? Or whether this is a limitation of an application deployed via TestFlight?
I have a terrible feeling I am chasing ghosts, and it may be a TestFlight limitation for exporting workouts?
Thanks
Topic:
App & System Services
SubTopic:
Health & Fitness
Tags:
Health and Fitness
HealthKit
TestFlight
I am writing to address a concern regarding the background permission functionality in my app, which is critical for ensuring user safety as they navigate various terrains. This feature also enables users to smoothly record their navigation tracks for review after their activities. Recently, I've noticed that this functionality is not working as seamlessly as before.
Additionally, I observed that the app is not categorized under 'health and fitness'—could reclassifying it improve background activity? Before I delve into a detailed code review, I wanted to check if this issue might be related to sync or settings on the App Store side, such as permission configurations, app updates, or other related factors. Or, is it more likely an issue stemming from the app’s codebase?
Topic:
App & System Services
SubTopic:
Maps & Location
Tags:
Maps Web Snapshots
Health and Fitness
Core Location
Background Tasks
I'm dealing with a strange bug where I am requesting read access for 'appleExerciseTime' and 'activitySummaryType', and despite enabling both in the permission sheet, they are being set to 'sharingDenied'.
I'm writing a Swift Test for making sure permissions are being granted.
@Test
func PermissionsGranted() {
try await self.manager.getPermissions()
for type in await manager.allHealthTypes {
let status = await manager.healthStore.authorizationStatus(for: type)
#expect(status == .sharingAuthorized, "\(type) authorization status is \(status)")
}
}
let healthTypesToShare: Set<HKSampleType> = [
HKQuantityType(.bodyMass),
HKQuantityType(.bodyFatPercentage),
HKQuantityType(.leanBodyMass),
HKQuantityType(.activeEnergyBurned),
HKQuantityType(.basalEnergyBurned),
HKObjectType.workoutType()
]
let allHealthTypes: Set<HKObjectType> = [
HKQuantityType(.bodyMass),
HKQuantityType(.bodyFatPercentage),
HKQuantityType(.leanBodyMass),
HKQuantityType(.activeEnergyBurned),
HKQuantityType(.basalEnergyBurned),
HKQuantityType(.appleExerciseTime),
HKObjectType.activitySummaryType()
]
let healthStore = HKHealthStore()
func getPermissions() async throws {
try await healthStore.requestAuthorization(toShare: self.healthTypesToShare, read: self.allHealthTypes)
}
After 'getPermissions' runs, the permission sheet shows up on the Simulator, and I accept all. I've double checked that the failing permissions show up on the sheet and are enabled. Then the test fails with:
Expectation failed: (status → HKAuthorizationStatus(rawValue: 1)) == (.sharingAuthorized → HKAuthorizationStatus(rawValue: 2)) HKActivitySummaryTypeIdentifier authorization status is HKAuthorizationStatus(rawValue: 1)
Expectation failed: (status → HKAuthorizationStatus(rawValue: 1)) == (.sharingAuthorized → HKAuthorizationStatus(rawValue: 2)) HKActivitySummaryTypeIdentifier authorization status is HKAuthorizationStatus(rawValue: 1)
With the rawValue of '1' being 'sharingDenied'. All other permissions are granted. Is there a workaround here, or something I'm potentially doing wrong?
Is there documentation on how to read workout effort scores from a HealthKit workout? I'm interested in reading workoutEffortScore and estimatedWorkoutEffortScore. I have not been successful trying to read them using the same method that I do other workout HKQuantityTypes (heartRate, stepCount, etc). I'm using Swift and I do have authorization for those types requested and granted.
I have found documentation on setting these values (https://developer.apple.com/forums/thread/763539) but not reading them.
Thank You
In my WatchOS app I've written the following code to check if my app has access to the user's health data:
func isHealthKitAuthorized() -> Bool {
let typesToRead: [HKObjectType] = [
HKObjectType.quantityType(forIdentifier: .heartRate)!,
HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!,
HKObjectType.quantityType(forIdentifier: .appleMoveTime)!,
HKObjectType.quantityType(forIdentifier: .appleExerciseTime)!,
HKObjectType.workoutType()
]
let typesToShare: Set<HKSampleType> = [
HKObjectType.workoutType(),
HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!,
HKObjectType.quantityType(forIdentifier: .heartRate)!
]
var isAuthorized = true
for type in typesToRead {
let status = healthStore.authorizationStatus(for: type)
if status != .sharingAuthorized {
print("Access denied to: \(type.identifier)")
isAuthorized = false
}
}
for type in typesToShare {
let status = healthStore.authorizationStatus(for: type)
if status != .sharingAuthorized {
print("Access denied to: \(type.identifier)")
isAuthorized = false
}
}
return isAuthorized
}
However for the appleMoveTime and appleExerciseTime types their status is returning as 'sharingDenied' (checked by printing the status' rawValue) even though they are authorized on the Watch's settings. This happened both on the simulator and on the Watch itself. Am I doing something wrong?
Hello,
My app syncs workout data from a third-party device and records workouts with HealthKit as follows:
let builder = HKWorkoutBuilder(healthStore: healthStore, configuration: hkConf, device: hkDevice)
try await builder.beginCollection(at: startDate)
try await builder.addSamples(samples)
try await builder.endCollection(at: endDate)
let workout = try await builder.finishWorkout()
let workoutRouteBuilder = HKWorkoutRouteBuilder(healthStore: healthStore, device: hkDevice)
try await workoutRouteBuilder.insertRouteData(filteredLocations)
try await workoutRouteBuilder.finishRoute(with: workout, metadata: nil)
However, I’m encountering two issues:
The workouts appear in Apple Fitness but do not contribute to the activity rings.
The workout includes a route (visible in the raw workout data in Apple Health) but does not display on Apple Fitness.
Is there any way to fix this? I’d appreciate any suggestions you might have.
__
I am working on an Apple Watch companion app to an existing live iOS app. I am utilizing the heart rate tracking for an active 'self-care' sauna session. I say self-care in quotes because it's more self-care than a workout activity, but it is closely blurring the lines between the two.
I have come to understand that if a session truly isn't a workout, then you should not use workoutSession.startActivity. However the app needs to function entirely like a workout would. This is not a meditation application. Sauna is actually just one of many activity types supported in the app.
I have tried using extended runtime session, and there have been numerous issues with doing so. It is not nearly as robust for the user. For example, the active session is not prioritized by the watch's CPU. Now playing is no longer functional. Heart rate is far more inconsistent, and this variable is as critical as if it were in a workout.
I have tried using HKWorkoutSession, however I worry the app will be rejected by doing so. This method works most accurately to collect the right data for the user, and prioritizes system resources as expected. The app can be moved to the background as expected and continue to communicate with the iOS app.
What is the best way to move forward here. It almost feels like I am operating in a grey area with no real solution in place. Any assistance is greatly appreciated as we would like to follow all guidelines while producing a high quality experience for our users.
In the fitness app under iOS 18, the location of all workouts is displayed on a small map.
For workouts with routes, I can already successfully read out the route and thus also determine the starting point. So that works.
For indoor workouts such as yoga or indoor rowing, the exact location is also displayed in the fitness app. I would now also like to read out this location for these indoor workouts in my app.
Does anyone know how to do this?
Hello,
I am building a workout app that has an option to add segments to differentiate different stages of the training session. Segments are added the following way:
func saveSegment(eventType: HKWorkoutEventType, startDate: Date, endDate: Date, inSeg: Int) async throws {
let dateInterval = DateInterval(start: startDate, end: endDate)
let event = HKWorkoutEvent(type: eventType, dateInterval: dateInterval, metadata: metadata)
try await builder?.addWorkoutEvents([event])
}
Inside Health -> Workouts -> Show All Data, the segments appear, but in Fitness app there are no segments. The workout is .paddleSports. I thought that maybe the workout type was the problem, but when I start the sessions from the native workout app, segments are added and shown in the Fitness app:
In other posts I saw suggested to add an event as .marker instead of .segment, but the result is the same, it does not appear.
Is there something I am doing wrong? How can I show the segments into the Fitness app?
Another question, I would like to add stroke rate and stroke count to my paddling session, is there a way to add it? Paddle Sports workout was recently introduced and it would be great to have the option to add those values.
Thank you in advance.
Inaki
Is it possible to develop the following app? The app will measure heart rate variability five times at 2-minute intervals triggered by an event and output the values.
Platform & Version:
iOS Version: 18.3.1
Development Environment: Xcode 16.2, macOS 14.6.1
Description of the Issue:
We're exploring ways to better integrate Apple Fitness+ workouts into our app. We've noticed that some third-party apps, such as Strava and HealthFit, now display Fitness+ workout details, including the title, trainer, and an image.
I’ve been investigating how this is possible, and the only relevant change I’ve found is that HKMetadataKeyAppleFitnessPlusCatalogIdentifier is now being set for Fitness+ workouts. However, I can’t find any public API or official documentation that explains how to use these identifiers to retrieve the associated workout details.
Question:
Is there an official API available to fetch metadata for Fitness+ workouts using these identifiers? Or are these third-party apps potentially accessing private APIs? If no API exists, is the only option to create a manual mapping of these identifiers—something that seems impractical given the constantly evolving Fitness+ workout catalog?
Any guidance on this would be greatly appreciated. Thanks!
Topic:
App & System Services
SubTopic:
Health & Fitness
Tags:
Health and Fitness
HealthKit
WorkoutKit