Hello.
I have NFC tags that I scan before walking my dog, that set off a list of shortcuts.
The shortcuts have been failing the last couple of weeks but were fine before that. seems to be a problem with linking to starting a walk in apple watch workouts?!
I have the latest iOS 18 public beta running (18.1) and watchOS 11.0.1
WorkoutKit
RSS for tagThe WorkoutKit framework provides the ability to create, preview, and schedule planned workouts for the Workout app on Apple Watch.
Posts under WorkoutKit tag
21 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
I've realised with the sample code from the WWDC video below I'm getting the following error when trying to use the iPhone simulator and apple watch simulator paired.
Whenever i try to test out the sample project I'm getting the following error.
Failed to send data: Error Domain=com.apple.healthkit Code=300 "Remote device is unreachable" UserInfo={NSLocalizedDescription=Remote device is unreachable, NSUnderlyingError=0x600000c9c900 {Error Domain=RPErrorDomain Code=-6727 "kNotFoundErr ('rapport:rdid:PairedCompanion' not found)" UserInfo={cuErrorDesc=kNotFoundErr ('rapport:rdid:PairedCompanion' not found), cuErrorMsg='rapport:rdid:PairedCompanion' not found, NSLocalizedDescription=kNotFoundErr ('rapport:rdid:PairedCompanion' not found)}}}
Is it not possible to not test out the new WorkoutKit mirroring API's using the simulator?
Currently right now if you run the project you'll notice that you can start a workout session on the iPhone > Apple Watch but there is no way to control and mirror on both devices at the moment i.e You can't control the iPhone app on the Apple Watch and vice versa.
Also because of this the iPhone can't send data to the Apple Watch i.e. pause, end, water etc. I'm guessing this is meant to be possible since it seems a bit strange to only be able to test this out with actual devices.
WWDC Session
https://developer.apple.com/wwdc23/10023
Sample Code
https://developer.apple.com/documentation/healthkit/workouts_and_activity_rings/building_a_multidevice_workout_app
Apple is using the RPE scale for workout effort scores. This stands for the Rate of Perceived Exertion. They're specifically using the CR-10 scale, at least from what I can tell by saving values to HealthKit. They only accept value between 0 and 10.
Has anyone been able to find a scientific or academic paper on how they have chosen their different effort breakouts?
Right from the Fitness app on iPhone and Activity app on Apple Watch:
1-3 Easy
4-6 Moderate
7-8 Hard
9-10 All Out
There is zero documentation on these new types, which makes it difficult for workout recording apps to properly and appropriately save this new data type. Sure, we can use the Apple apps as a reference, but since there isn't a built-in Apple SwiftUI sheet to present this data, and no references to academia to point our users to, our solutions would just look the same.
FB15315876 - Documentation / HealthKit: Publish documentation about .workoutEffortScore and .estimatedWorkoutEffortScore
FB15316109 - Documentation / HealthKit: Add documentation to .estimatedWorkoutEffortScore and .workoutEffortScore that you can't save those samples via the save API and that they must be related and let that API save the sample
FB15316251 - Documentation / HealthKit: Add documentation for acceptible values of .estimatedWorkoutEffortScore and .workoutEffortScore - don't rely on a runtime error!
Apple missed making an enum for all third party developers this year.
Hi everyone,
I’m reaching out to see if anyone else has experienced issues with the workoutPreview API. I’ve been trying to get it to send workouts to the Apple Watch, but it’s not working as expected. Even the example code provided in the official documentation fails to do the job.
For reference, I’m using the latest stable (non-beta) versions of iOS and watchOS.
import SwiftUI
import WorkoutKit
struct PresentPreviewDemo: View {
private let cyclingWorkoutPlan: WorkoutPlan
@State var showPreview: Bool = false
init() {
cyclingWorkoutPlan = WorkoutPlan(.custom(WorkoutStore.createCyclingCustomWorkout()))
}
var body: some View {
Button("Present Cycling Workout Preview") {
showPreview.toggle()
}
.workoutPreview(cyclingWorkoutPlan, isPresented: $showPreview)
}
}
struct PresentPreviewDemo_Previews: PreviewProvider {
static var previews: some View {
PresentPreviewDemo()
}
}
It used to work but it is not working anymore.
Has anyone else run into this problem? Is there a known issue or workaround that I might have missed? I’ve tried everything I can think of, and this is blocking my progress.
Any insights or suggestions would be greatly appreciated!
Thanks in advance!
Hi! I've added the code of the multidevice workout app from Apple to my app and I found some issues that I cannot see on the sample app.
In my app, to pause or end the workout from the watch, the iOS companion app has to be opened or at least on background, but never closed.
What I'm doing wrong?
Hey folks, a couple of questions regarding WorkoutKit:
What happened to validation errors? They are mentioned in the WWDC23 video, but no longer are present in the API. It seems a fatal error is thrown if the workout fails validation (for example setting a negative distance in a workout goal).
What is the logic of the WorkoutScheduler, if we try to add more workouts than is allowed? If the limit is 50, what happens when we try to add a 51st? Are workouts de-queued based on date or anything? API documentation is very sparse
Do completed workouts and workouts with a scheduled date in the past stay in the WorkoutScheduler? Are we responsible for removing these? I guess my overall question regarding the WorkoutScheduler is, what are we responsible for managing and what is handled gracefully for us.
None of these answers seem to be openly available, but if anyone know anecdotally or even better from the WorkoutKit team, I'd be very grateful!
Thanks!
I think I know the answer to this question, but is there any way to 'manually' add distance to a SingleGoalWorkout? I.e., I want to make a SingleGoalWorkout with a location set to .indoor, and then add any meters the user has covered from a BLE Fitness Machine Device (exercise bike, indoor rower etc.) towards the workout goal. Is this possible?
The session Build custom swimming workouts with WorkoutKit mentions Outdoor activities supporting distance goals and lists:
Cycling
Running
Hiking
Walking
Swimming
Wheelchair walk + run
And new:
Golf
Rowing
Downhill skiing
Snowboarding
Lacrosse
Hockey
Disc Sports
Skating
Paddle sports
Soccer
American football
Australian football
Rugby
Cross country skiing
I know the previous 6 have GPS tracks saved with the workout in Health.
Do all of the other ones now also save the GPS track to Health?
If not all of them, which do?
Hello,
I’m currently developing a fitness app for watchOS that lets a user to manually set a desired heart rate target zone (enter numbers representing the lower and upper boundaries) and start a workout (right now it’s only “Other” type).
After that my app monitors user’s heart rate and alerts them when they’re out of zone.
When user ends the workout, the info about this workout appears on “Fitness” iOS app, and user can see the workout data like Workout Time, Active and Total Calories, Avg. Heart Rate.
Also user can see Heart Rate chart with info how their heart rate was changing during a workout (see the Figure 1).
Now to the question.
When user clicks “Show More” button above the Heart Rate chart, they can see the same Heart Rate chart and another one, with Post-Workout Heart Rate (see the Figure 2).
But there is no “Estimated time in each heart rate zone” as one can see in the workout’s details that were recorded from Apple’s workout (watchOS “Workout” app, for a workout of “Other” type as well). Please see the Figure 3.
The question is: is it possible to add “Estimated time in each heart rate zone” to workout recorded via my third-party app so it would look like on the Figure 3 in "Fitness" iOS app, and if it's possible, what steps should I undertake to implement this ?
Thanks in advance!
I posted the screenshots in the replies to the post, because otherwise I was not able to submit a post ("sensitive language" warning, I suspect it's because of the ids in the attached screenshot's urls)
Hello,
I am using the project from https://developer.apple.com/documentation/healthkit/workouts_and_activity_rings/building_a_multidevice_workout_app
The workout is starting on the watch and I can see the metrics, but it seems the mirroring with the phone is not working, I am getting this errors
[mirroring] <HKWorkoutSession:0x600002c10100 57C340BA-2AA9-4477-9AC8-181698A526A5 running [Primary]>: Failed to send data to remote session with error: Error Domain=com.apple.healthkit Code=300 "Remote device is unreachable" UserInfo={NSLocalizedDescription=Remote device is unreachable, NSUnderlyingError=0x600000c53b70 {Error Domain=RPErrorDomain Code=-6727 "kNotFoundErr ('rapport:rdid:PairedCompanion' not found)" UserInfo={cuErrorDesc=kNotFoundErr ('rapport:rdid:PairedCompanion' not found), cuErrorMsg='rapport:rdid:PairedCompanion' not found, NSLocalizedDescription=kNotFoundErr ('rapport:rdid:PairedCompanion' not found)}}}
Does anybody else has this issue?
Thank you
The WWDC23 session number 10016 is referring to a way to generate .workout files (timecode 09:43) in both binary and JSON format.
Unfortunately, the API seems to have changed:
CustomWorkoutComposition renamed to CustomWorkout
.dataRepresentation disappeared
Ideally I would like to generate .workout files directly in JSON format but there is no specifications published and no documentation to generate them.
Any idea where I should look?
Hello fellow developers,
I've recently developed a workout companion watch app for iOS. However, I'm now have a task of implementing custom workouts for my app. I've come across a video demonstrating how to create and schedule custom workouts for the watch app, which I believe will be incredibly helpful for my project.
Video Link: Creating Custom Workouts for iOS Watch App
If anyone knows of any additional resources, such as articles or videos, that further explores this topic, I would greatly appreciate it if you could share them with me.
Thank you for your assistance!
Best regards,
Pranit Bhogale
Please reference the Sample Planner app which can be found at the below link.
https://developer.apple.com/documentation/WorkoutKit/customizing-workouts-with-workoutkit.
In WorkoutStore.swift, all of the values are hard coded. I would like to turn them into variables stored in @EnvironmentObject (WorkoutStoreValue).
With the below code, using "singleRunStartDelay" as a trial, I can get that variable passed to the WorkStore struct only when the app is first opened, however, I have not been able to get it changed in realtime.
I need help with changing the WorkoutStore struct to have the values updated in realtime. I have tried changing the func from static but that gives an error (Instance member 'createSingleRunWorkout' cannot be used on type 'WorkoutStore'; did you mean to use a value of this type instead?)
I'm now learning Xcode/SwiftUI. I have been stuck for about four day trying many different ideas.
Thanks
// Copyright © 2024 Apple. All rights reserved.
/*
The structure that returns running workout compositions.
*/
import HealthKit
import WorkoutKit
import SwiftUI
import Foundation
struct WorkoutStore{
@EnvironmentObject var workoutStoreValue: WorkoutStoreValue
static func createSingleRunWorkout() -> CustomWorkout {
let getReadyStep = WorkoutStep(goal: .open) //fixed to .open
let singleRunDelay = WorkoutStoreValue.shared.singleRunStartDelay
var onYourMarkStep = IntervalStep(.work)
onYourMarkStep.step.goal = .time(Double(singleRunDelay), .seconds) //you have this much time to start
var runStep = IntervalStep(.work)
runStep.step.goal = .distance(100, .meters) //hard coded for now. Need to insert distance variable here
runStep.step.alert = .speed(3...4, unit: .metersPerSecond, metric: .current) // Would like to insert alert variables here
var block = IntervalBlock()
block.steps = [
onYourMarkStep,
runStep
]
block.iterations = 1 //fixed at 1. Would like to insert as a variable
return CustomWorkout(activity: .running,
location: .outdoor,
displayName: "Single run mode",
warmup: getReadyStep,
blocks: [block])
}
}
Hi experts,
I got an Ultra2 a while ago and has been using it on walking / running exercise.
Recently I came across to this apple site: debug profile and I'm curious about what I would get during the exercise.
So I follow the instruction and install the location services profile. After getting the sysdiagnose report, I try to get location related information from it. And it seems that the log from "locationd" and "gpsd" are what I'm looking for.
But when I try to look into the nmea information, I found out the sysdiagnose only provide around 10-15 mins of nmea data.
For example, let's say I have a walking exercise from 0900 - 1000, but I can only see nmea data from 0945 - 1000. The data from 0900 to 0945 can't be found in the sysdiagnose.
Not sure if's the limitation or any setting I can change to increase the logging period?
Thanks.
Hi there,
I'm new here, looking for a step-by-step tutorial that will help me to achieve my first step.
https://developer.apple.com/documentation/workoutkit/customizing-workouts-with-workoutkit
downloaded the WorkoutKit sample file.
try to run, and connect to my account and team but get an error to connect a device.
Your team has no devices from which to generate a provisioning profile. Connect a device to use or manually add device IDs in Certificates, Identifiers & Profiles. https://developer.apple.com/account/
"
I logged in to my web account but didn't find any device IDs in Certificates, Identifiers & Profiles section
Hi.
is it possible to create a Custom Workout with different activity types.
I want a Custom Workout where the user first has to run and after do skiing.
Its like a little bit like SwimBikeRun but with running and Skiing.
How can i do this?
Thank you
Hello, it is discussed here https://developer.apple.com/videos/play/wwdc2023/10016/ (12:16) regarding WorkoutComposition, but unfortunately, I cannot find this class or structure in the documentation. Has this concept been removed?
With CustomWorkout, I can assign a name (displayName) to workouts, which also appears in the Workout app. Unfortunately, this parameter is missing for common workouts such as SingleGoalWorkout. Is there a reason for this? I find it inconvenient when the name is missing
CustomWorkout
init(activity: HKWorkoutActivityType, location: HKWorkoutSessionLocationType, displayName: String?, warmup: WorkoutStep?, blocks: [IntervalBlock], cooldown: WorkoutStep?)
SingleGoalWorkout
init(activity: HKWorkoutActivityType, location: HKWorkoutSessionLocationType, swimmingLocation: HKWorkoutSwimmingLocationType, goal: WorkoutGoal)
https://idmsa.apple.com/IDMSWebAuth/signin?path=%2F%2Fforums%2Fpost%2Fquestion%3Flogin%3Dtrue&language=US-EN&instanceId=EN&appIdKey=25138a77e3499638936f018102a53961c923f72b517d4a4d6aee9f09529baca9&rv=4
I've built and tested the code obtained from this site, but although the session starts, pausing or stopping it doesn't seem to work properly. Does anyone know what might be causing this issue?
I'm using the latest versions of iOS and watchOS, and my Xcode is version 15.0.1.
The main code is as follows, and the session does not start properly in startWorkout.
import Foundation
import os
import HealthKit
@MainActor
class WorkoutManager: NSObject, ObservableObject {
struct SessionSateChange {
let newState: HKWorkoutSessionState
let date: Date
}
@Published var sessionState: HKWorkoutSessionState = .notStarted
@Published var heartRate: Double = 0
@Published var activeEnergy: Double = 0
@Published var speed: Double = 0
@Published var power: Double = 0
@Published var cadence: Double = 0
@Published var distance: Double = 0
@Published var water: Double = 0
@Published var elapsedTimeInterval: TimeInterval = 0
@Published var workout: HKWorkout?
let typesToShare: Set = [HKQuantityType.workoutType(),
HKQuantityType(.dietaryWater)]
let typesToRead: Set = [
HKQuantityType(.heartRate),
HKQuantityType(.activeEnergyBurned),
HKQuantityType(.distanceWalkingRunning),
HKQuantityType(.cyclingSpeed),
HKQuantityType(.cyclingPower),
HKQuantityType(.cyclingCadence),
HKQuantityType(.distanceCycling),
HKQuantityType(.dietaryWater),
HKQuantityType.workoutType(),
HKObjectType.activitySummaryType()
]
let healthStore = HKHealthStore()
var session: HKWorkoutSession?
#if os(watchOS)
var builder: HKLiveWorkoutBuilder?
#else
var contextDate: Date?
#endif
let asynStreamTuple = AsyncStream.makeStream(of: SessionSateChange.self, bufferingPolicy: .bufferingNewest(1))
static let shared = WorkoutManager()
private override init() {
super.init()
Task {
for await value in asynStreamTuple.stream {
await consumeSessionStateChange(value)
}
}
}
/**
Consume the session state change from the async stream to update sessionState and finish the workout.
*/
private func consumeSessionStateChange(_ change: SessionSateChange) async {
sessionState = change.newState
/**
Wait for the session to transition states before ending the builder.
*/
#if os(watchOS)
/**
Send the elapsed time to the iOS side.
*/
let elapsedTimeInterval = session?.associatedWorkoutBuilder().elapsedTime(at: change.date) ?? 0
let elapsedTime = WorkoutElapsedTime(timeInterval: elapsedTimeInterval, date: change.date)
if let elapsedTimeData = try? JSONEncoder().encode(elapsedTime) {
await sendData(elapsedTimeData)
}
guard change.newState == .stopped, let builder else {
return
}
let finishedWorkout: HKWorkout?
do {
try await builder.endCollection(at: change.date)
finishedWorkout = try await builder.finishWorkout()
session?.end()
} catch {
Logger.shared.log("Failed to end workout: \(error))")
return
}
workout = finishedWorkout
#endif
}
}
// MARK: - Workout session management
//
extension WorkoutManager {
func resetWorkout() {
#if os(watchOS)
builder = nil
#endif
workout = nil
session = nil
activeEnergy = 0
heartRate = 0
distance = 0
water = 0
power = 0
cadence = 0
speed = 0
sessionState = .notStarted
}
func sendData(_ data: Data) async {
do {
try await session?.sendToRemoteWorkoutSession(data: data)
} catch {
Logger.shared.log("Failed to send data: \(error)")
}
}
}
extension WorkoutManager: HKWorkoutSessionDelegate {
nonisolated func workoutSession(_ workoutSession: HKWorkoutSession,
didChangeTo toState: HKWorkoutSessionState,
from fromState: HKWorkoutSessionState,
date: Date) {
Logger.shared.log("Session state changed from \(fromState.rawValue) to \(toState.rawValue)")
let sessionSateChange = SessionSateChange(newState: toState, date: date)
asynStreamTuple.continuation.yield(sessionSateChange)
}
nonisolated func workoutSession(_ workoutSession: HKWorkoutSession,
didFailWithError error: Error) {
Logger.shared.log("\(#function): \(error)")
}
nonisolated func workoutSession(_ workoutSession: HKWorkoutSession,
didDisconnectFromRemoteDeviceWithError error: Error?) {
Logger.shared.log("\(#function): \(error)")
}
nonisolated func workoutSession(_ workoutSession: HKWorkoutSession,
didReceiveDataFromRemoteWorkoutSession data: [Data]) {
Logger.shared.log("\(#function): \(data.debugDescription)")
Task { @MainActor in
do {
for anElement in data {
try handleReceivedData(anElement)
}
} catch {
Logger.shared.log("Failed to handle received data: \(error))")
}
}
}
}
private func startWorkout() {
Task {
do {
let configuration = HKWorkoutConfiguration()
configuration.activityType = .cycling
configuration.locationType = .outdoor
try await workoutManager.startWorkout(workoutConfiguration: configuration)
} catch {
Logger.shared.log("Failed to start workout \(error))")
}
}
}
Hi,
Is there anyway to share a WorkoutScheduler across an iPhone and watch app? If I create a scheduler on the phone app the watch app can't see it and creates its own. I'm using WorkoutScheduler.shared.scheduledWorkouts but end up with two identical sections at the top of the workout app
Thanks