When does appleExerciseTime update or change?

I've been trying to figure out what the bare minimum is required for HKWorkoutBuilder to create a workout that adds time the appleExerciseTime. I couldn't find the documentation for this. This is my code so far.

func createWorkoutSample(
    expectedActiveEnergyData: [Double],
    expectedExerciseMinutesData: [Double],
    calendar: Calendar,
    startDate: Date
) async throws -> [HKSample] {
    var testData: [HKSample] = []
    let workoutConfiguration = HKWorkoutConfiguration()
    workoutConfiguration.activityType = .running
    workoutConfiguration.locationType = .outdoor

    let results = try await withThrowingTaskGroup(of: HKSample?.self) { group in
        for (index) in 0..<expectedActiveEnergyData.count {
            guard let date = calendar.date(byAdding: .day, value: index, to: startDate) else {
                continue
            }
            
            group.addTask {
                let builder = HKWorkoutBuilder(
                    healthStore: self.manager.healthStore,
                    configuration: workoutConfiguration,
                    device: .local()
                )
                let endDate = date.addingTimeInterval(expectedExerciseMinutesData[index] * 60)
                
                try await builder.beginCollection(at: date)
                
                let energyType = HKQuantityType.quantityType(
                    forIdentifier: .activeEnergyBurned
                )!
                let energyQuantity = HKQuantity(
                    unit: HKUnit.kilocalorie(),
                    doubleValue: expectedActiveEnergyData[index]
                )
                let energySample = HKQuantitySample(
                    type: energyType,
                    quantity: energyQuantity,
                    start: date,
                    end: endDate
                )

                return try await withCheckedThrowingContinuation { continuation in
                    builder.add([energySample]) { (success, error) in
                        if let error = error {
                            continuation.resume(throwing: error)
                            return
                        }

                        builder.endCollection(withEnd: endDate) { (success, error) in
                            if let error = error {
                                continuation.resume(throwing: error)
                                return
                            }

                            builder.finishWorkout { (workout, error) in
                                if let error = error {
                                    continuation.resume(throwing: error)
                                    return
                                }
                                continuation.resume(returning: workout)
                            }
                        }
                    }
                }
            }
        }

        for try await workout in group {
            if let workout = workout {
                testData.append(workout)
            } else {
                print("Skipping nil workout result.")
            }
        }
        return testData
    }

    print("Total samples created: \(results.count)")
    return results
}

When I query appleExerciseTime, there are no results. I've looked at the HKWorkoutBuilder documentation, and most of the information expands on adding samples related to the deprecated HKWorkout.

Answered by DTS Engineer in 820429022

I’m able to see the exercises in the Fitness app along with their times, but the green ring doesn’t fill up.

The green ring not changing is probably because your workout doesn't have the .distanceWalkingRunning sample. Here is the code that works for me:

let endDate: Date = .now
let startDate = endDate.addingTimeInterval(-30 * 60) // 30 minutes before.

try await workoutBuilder.beginCollection(at: startDate)

let energySample = HKQuantitySample(type: HKQuantityType.quantityType(forIdentifier: .activeEnergyBurned)!,
                                    quantity: HKQuantity(unit: HKUnit.kilocalorie(), doubleValue: 300),
                                    start: startDate, end: endDate)
let distanceSample = HKQuantitySample(type: HKQuantityType.quantityType(forIdentifier: .distanceWalkingRunning)!,
                                      quantity: HKQuantity(unit: HKUnit.mile(), doubleValue: 3),
                                      start: startDate, end: endDate)
try await workoutBuilder.addSamples([energySample, distanceSample])

try await workoutBuilder.endCollection(at: endDate)

if let workout = try await workoutBuilder.finishWorkout() {
    print("\(workout)")
} else {
    print("Failed to finish workout!")
}

To retrieve the .appleExerciseTime samples, note that they are not associated with a workout, and so you should use the workout duration as the predicate:

let predicate = HKQuery.predicateForSamples(withStart: workout.startDate, end: workout.endDate)
let query = HKSampleQuery(sampleType: HKQuantityType(.appleExerciseTime),
                          predicate: predicate,
                          limit: HKObjectQueryNoLimit,
                          sortDescriptors: []) { (_, results, error) in
    results?.forEach { sample in
        if let quantity = sample as? HKQuantitySample {
            print(quantity)
        }
    }
}
healthStore.execute(query)

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

After adding the workout sample with your code, can you find it in Health.app and Fitness.app, and do you see that the exercise minute in Fitness.app (the green ring) increases?

Assuming that you successfully create a workout sample on iOS, HealthKit should generate the exercise minute sample for you with the workout duration.

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

I’m able to see the exercises in the Fitness app along with their times, but the green ring doesn’t fill up.

The green ring not changing is probably because your workout doesn't have the .distanceWalkingRunning sample. Here is the code that works for me:

let endDate: Date = .now
let startDate = endDate.addingTimeInterval(-30 * 60) // 30 minutes before.

try await workoutBuilder.beginCollection(at: startDate)

let energySample = HKQuantitySample(type: HKQuantityType.quantityType(forIdentifier: .activeEnergyBurned)!,
                                    quantity: HKQuantity(unit: HKUnit.kilocalorie(), doubleValue: 300),
                                    start: startDate, end: endDate)
let distanceSample = HKQuantitySample(type: HKQuantityType.quantityType(forIdentifier: .distanceWalkingRunning)!,
                                      quantity: HKQuantity(unit: HKUnit.mile(), doubleValue: 3),
                                      start: startDate, end: endDate)
try await workoutBuilder.addSamples([energySample, distanceSample])

try await workoutBuilder.endCollection(at: endDate)

if let workout = try await workoutBuilder.finishWorkout() {
    print("\(workout)")
} else {
    print("Failed to finish workout!")
}

To retrieve the .appleExerciseTime samples, note that they are not associated with a workout, and so you should use the workout duration as the predicate:

let predicate = HKQuery.predicateForSamples(withStart: workout.startDate, end: workout.endDate)
let query = HKSampleQuery(sampleType: HKQuantityType(.appleExerciseTime),
                          predicate: predicate,
                          limit: HKObjectQueryNoLimit,
                          sortDescriptors: []) { (_, results, error) in
    results?.forEach { sample in
        if let quantity = sample as? HKQuantitySample {
            print(quantity)
        }
    }
}
healthStore.execute(query)

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

When does appleExerciseTime update or change?
 
 
Q