How to save a workout with a route on a locked iPhone ?

This question is a follow-up of https://developer.apple.com/forums/thread/695853

I need to save a workout with a route from a locked iPhone. I've tried many different ways of saving it since more than one year but I still struggle to find a code which works when the phone is locked.

My current code is :

      let healthStore = HKHealthStore()
      let workoutConfiguration = HKWorkoutConfiguration()
      workoutConfiguration.activityType = .running
      let builder = HKWorkoutBuilder(healthStore: healthStore,
                                      configuration: workoutConfiguration,
                                      device: .local())
      try await builder.beginCollection(at: workout.start)
      guard let quantityType = HKQuantityType.quantityType(forIdentifier: .activeEnergyBurned) else { ... }
      let totalEnergyBurnedSample = HKCumulativeQuantitySample(type: quantityType, quantity: HKQuantity(unit: HKUnit.kilocalorie(), doubleValue: totalEnergyBurned), start: workout.start, end: workout.end)
      try await builder.addSamples([totalEnergyBurnedSample])

      if let route = builder.seriesBuilder(for: .workoutRoute()) as? HKWorkoutRouteBuilder {
        try await route.insertRouteData(locations)
      } else {
        Logger.health.error("Error creating the route builder! Skipping location addition to HealthKit workout.")
      }
      try await builder.endCollection(at: workout.end)

      let hkFinishedWorkout = try await builder.finishWorkout()


      Logger.health.info("Workout saved successfully.")

    } catch {
      Logger.health.error("Failed to save workout: \(String(describing: error))")
    }

I naively though that by getting the HKWorkoutRouteBuilder from the HKWorkoutBuilder, the finishWorkout() method would link both of them, but this code never reports an error and the route is associated with the workout only when the iPhone is unlocked when saving. If this code is executed on a locked iPhone, the workout is created, the route is created (both can be seen in the Health application) but the route is not associated with the workout. I can't call finishRoute(with: hkworkout, metadata: nil) on the HKWorkoutRouteBuilder as it requires the HKWorkout which the HKWorkoutBuilder does not return when the phone is locked ;-(

Is there a way to create a workout with an associated route on a locked iPhone ?

I think I finally have found a way to save a workout with a route even when the iPhone is locked.

TLDR: We should create the workout ourselves and not use a HKWorkoutBuilder.

I use the following code:

let healthStore = HKHealthStore()
let energyBurned = HKQuantity(unit: HKUnit.kilocalorie(), doubleValue: totalEnergyBurned)
let distance = HKQuantity(unit: HKUnit.meter(), doubleValue: workout.distance)
let hkworkout = HKWorkout(activityType: .running,
                          start: workout.start,
                          end: workout.end,
                          duration: workout.duration,
                          totalEnergyBurned: energyBurned,
                          totalDistance: distance,
                          metadata: nil)
try await healthStore.save(hkworkout)
let route = HKWorkoutRouteBuilder(healthStore: healthStore, device: .local())
try await route.insertRouteData(locations)
try await route.finishRoute(with: hkworkout, metadata: nil)

The tip is to directly create the workout as the HKWorkoutBuilder.finishWorkout() would return nil on a locked iPhone (why?) and then use a HKWorkoutRouteBuilder and call finishRoute() with the created workout.

Hope it will help others.

I though that the code above was working (I did a quick test), but after this morning run, the workout saving failed...

When this code is executed on a locked iPhone I get the following log:

Whereas when saving from an unlocked iPhone I get :

It seems that the healthStore.save(hkworkout) method do not really save the workout when the iPhone is locked :-(

I will try to manually add the locations to the workout without using the HKWorkoutRouteBuilder...

@HealthKit team, any tip on how to save a workout with a route on a locked iPhone ?

Did you resolve your issue? I had the same problem and can provide some guidance. Before saving the route I first check UIApplication.shared.isProtectedDataAvailable to see if HealthKit is locked. If it locked, then I basically postpone adding the route to the workout until the user unlocks the phone. I give the user a voice alert to open the app so the route can be saved. This is a big hack and I wish Apple would provide a better solution to saving workouts and routes when the phone is locked.

How to save a workout with a route on a locked iPhone ?
 
 
Q