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
Activity
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
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!
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
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.
Hi everyone!
I'm trying to get the total sleep time for a given day, but users report that there's a difference between what my app reports and what the Apple Health app reports. In particular, we're off by 2 minutes less on average.
What we're doing is:
Get all the samples that are either core, deep, rem or unspecified
Cut-off time at 3 PM previous day
Merge overlapping intervals
Add all the remaining intervals
For debugging purposes I'm storing and sending all the raw samples to a server, and I have run tests and I don't find anything wrong. It looks like the number we come up with is correct according to our own rules. I wonder, how is Apple adding up all the samples to arrive at a number that's slightly off to our number.
Any insight would be appreciated. Thanks.
I am developing a React Native app for a health monitoring device that connects via Bluetooth and streams live data on iOS. To ensure the uniqueness of the device, I initially planned to use the MAC address. However, I discovered that iOS does not provide access to the original MAC address due to privacy restrictions.
Is there an alternative approach to uniquely identifying a Bluetooth device in iOS? I need a reliable way to distinguish devices while maintaining secure and stable connections.
Any insights or best practices on handling this in iOS would be greatly appreciated.
Looking forward to hearing your suggestions! If anyone has experience with handling Bluetooth device uniqueness on iOS, please share your insights. Thank you!
Topic:
App & System Services
SubTopic:
Core OS
Tags:
macOS
Health and Fitness
Core Bluetooth
Privacy
The WatchOS developer is not allowed to obtain healthKit permission status. The result is always unauthorized (either by clicking the dot/cross in the upper left corner or by turning on all Health, on some, off all).
WatchOS 开发获取 healthKit 的权限状态authorizationStatus不准。结果始终都是未授权(无论是点击左上角的点叉号还是开启全部健康项开关,开启部分,关闭所有),怎么处理?
Hello,
I’m developing an iOS app that works with sleep data from Apple Watch via HealthKit. I would like to clarify the following:
How can an iPhone app detect when a sleep session ends on the Apple Watch?
When is sleep data typically written to the HealthKit store on iPhone after sleep ends? Is it immediately after wake-up, or does it depend on certain conditions (e.g., watch charging, connectivity)?
Understanding the timing and mechanism of sleep data synchronization is crucial for our app to process accurate and timely health information.
Thank you for your assistance.
My research group is using watch sensors (accelerometers, gyroscopes) to track wrist motion to detect and measure eating. https://cecas.clemson.edu/ahoover/bite-counter/
We are running an HKWorkoutSession on the watch so that the app can run for an extended period of time (up to 12 hr) and continue to sense and process motion data.
Our app is adding to the activity rings, making it look like the user is exercising the entire time our app is running. Is there a method to prevent our app from contributing to the activity ring measures?
Topic:
App & System Services
SubTopic:
Health & Fitness
Tags:
WatchKit
Health and Fitness
SensorKit
WorkoutKit
Based on Cooordinate with the companion app in this article by Apple
https://developer.apple.com/documentation/healthkit/running-workout-sessions
if a workout were to be started on the iPhone companion app but with no Watch available, given HKLiveWorkoutBuilder not available in iOS, does the iPhone app need to implement it's own workout tracking such as a timer for counting the elapsed time and location updates for distance and GPS tracking?
If so in an instance where a paired Apple Watch were to exist and the workout is continued in the Watch app should the iPhone companion app stop this custom workout tracking and revert to the mirrored workout from the Watch to ensure accurate and synchronised data between the apps?
读取是不是解析 metadata 的对应键来获取值对吧~但我看了相关开发文档好像没找到这个的键是什么~于是也没法写入到对应的,现在只能自定义键来进行写入
但是这样写入后无法显示在心情下方的影响因素后面~
这个 key 是没公开的吗还是说我方法弄错了~请各位大大指教
We are working on the health related application and use apple health kit to sync the data from different devices like watches or ring.
We are targeting oura ring to get sleep and other parameters data. We are able to sync the data from oura for all other parameters (like pulse, respiratory rate, blood pressure, etc..) other than sleep. Surprisingly, sleep data that comes through other devices is syncing as expected from the health kit. We are even getting the data which is added manually in health kit. The only sleep data not syncing is from oura.
Can we get a document or any kind of help to sync the data from oura in to our application using health kit?
I'm reading hourly statistics from HealthKit using executeStatisticsCollectionQuery (code below).
Expectation
What I expect is to get back the list with one row per hour, where each hours has the same cumulative sum value.
Actual result
In results, first hour always contains less calories than next hours, which all have the same value.
Example:
Start: 2025-06-02T00:00:00+03:00, anchor: 2025-06-02T00:00:00+03:00, end: 2025-06-02T12:00:00+03:00
🟡 2025-06-02T00:00:00+03:00 Optional(50.3986 kcal)
🟡 2025-06-02T01:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T02:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T03:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T04:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T05:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T06:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T07:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T08:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T09:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T10:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T11:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T12:00:00+03:00 Optional(14.0224 kcal)
As you can see, here we have 2025-06-02T00:00:00+03:00 Optional(50.3986 kcal)
Now, if I add one more hour to the request (from beginning of time window), the same hour has proper calories count, while newly added hour, has wrong value):
2025-06-01T23:00:00+03:00, anchor: 2025-06-01T23:00:00+03:00, end: 2025-06-02T12:00:00+03:00.
🟡 2025-06-01T23:00:00+03:00 Optional(50.3986 kcal)
🟡 2025-06-02T00:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T01:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T02:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T03:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T04:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T05:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T06:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T07:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T08:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T09:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T10:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T11:00:00+03:00 Optional(64.421 kcal)
🟡 2025-06-02T12:00:00+03:00 Optional(14.0224 kcal)
And now first hour of the day, magically has more calories burned: 2025-06-02T00:00:00+03:00 Optional(64.421 kcal)
I suspect similar things happen with other quantity types, but haven't yet found a way to reproduce it.
Am I doing something wrong or is it a bug in HealthKit?
Code
let anchorDate = startDate
let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: [.strictStartDate])
healthStore.executeStatisticsCollectionQuery(
quantityType: .basalEnergyBurned,
quantitySamplePredicate: predicate,
options: [.separateBySource, .cumulativeSum],
anchorDate: anchorDate,
intervalComponents: DateComponents(hour: 1),
initialResultsHandler: { statistics, error in
if let error = error {
log(.error, "Error retrieving steps: \(error.localizedDescription)")
continuation.resume(throwing: SpikeException("Error retrieving steps: \(error.localizedDescription)"))
return
}
if let statistics {
let f = ISO8601DateFormatter()
f.timeZone = TimeZone.current
for s in statistics {
log(.debug, "\(f.string(from: s.startDate)) \(s.sumQuantity())")
}
}
continuation.resume(returning: statistics ?? [])
}
)
I want to know , how many days will the data of health stays in apple watch . For example, I have not synced the watch with iPhone for two weeks . Then When I synced it , I am only able to see the last week data on iPhone of the watch . Is it true ?
Hi everyone,
I'm building a health-focused iOS and watchOS app that uses WatchConnectivity to sync real-time heart rate and core body temperature data from iPhone to Apple Watch. While the HealthKit integration works correctly on the iPhone side, I'm facing persistent issues with WatchConnectivity — the data either doesn't arrive on the Watch, or session(_:didReceiveMessage:) never gets triggered.
Here's the setup:
On iPhone: Using WCSession.default.sendMessage(_:replyHandler:errorHandler:) to send real-time values every few seconds.
On Apple Watch: Implemented WCSessionDelegate, and session(_:didReceiveMessage:) is supposed to update the UI.
Both apps have WCSession.isSupported() checks, activate the session, and assign delegates correctly.
The session state shows isPaired = true and isWatchAppInstalled = true.
Bluetooth and Wi-Fi are on, both devices are unlocked and nearby.
Despite all this, the Watch never receives messages in real-time. Sometimes, data comes through in bulk much later or not at all.
I've double-checked Info.plist configurations and made sure background modes include "Uses Bluetooth LE accessories" and "Background fetch" where appropriate.
I would really appreciate guidance on:
Best practices for reliable, low-latency message delivery with WatchConnectivity.
Debugging steps or sample code to validate message transmission and reception.
Any pitfalls related to UI updates from the delegate method.
Happy to share further details. Thanks in advance!
Topic:
App & System Services
SubTopic:
Networking
Tags:
Watch Connectivity
Health and Fitness
watchOS
Apple Watch