1

I am building a running workout for Apple Watch and I have a problem to implement an "auto-pause" feature. The HKWorkoutSessionDelegate : workoutSession(_:didGenerate:) delegate is supposed to get some pause events generated by the system.

The problem I encounter is that my session never starts: the pause event is immediately sent to the delegate.

My code:

func workoutSession(_ workoutSession: HKWorkoutSession, didGenerate event: HKWorkoutEvent) {
            // press 2 buttons
            if(event.type == HKWorkoutEventType.pauseOrResumeRequest) {
                print("Detected Press")
                if workoutData.isPaused == false {
                    pauseWorkout()
                }
                else {
                    resumeWorkout()
                }
            }

            // Auto-pause
            if event.type == HKWorkoutEventType.motionPaused && workoutSettings.autoPause {
                print("Auto Pause")
                pauseWorkout()
            }
            if event.type == HKWorkoutEventType.motionResumed && workoutSettings.autoPause {
                print("Auto Resume")
                resumeWorkout()
            }
        }

The problem occurs into "// Auto-pause" section. Have I missed something ?

  • I have found the main issue: when I receive the auto-pause event, I put the HKWorkoutSession in "pause" mode. Then, the sessions paused and doesn't generate any resume event automatically. So I have to avoid pausing the HKWorkoutSession. The difficulty is to take into account the duration of the workout (because the builder elapsedTime continues to increase during auto pause if I don't pause the HKWorkoutSession). I have to check how to modify the workout duration before saving to HealthKit – Raphaël Barthomeuf Jun 18 '20 at 09:31
  • So ... After investigating, I am facing another issue. The HKLiveWorkoutBuilder is able to take care of manual pauses in elapsed time because we are able to use pause() and resume() methods of HKWorkoutSession. But for motionPaused and motionresumenl, we can't use these methods and the builder is not stopping the elapsed time while auto-pause. Does anyone has a suggestion ? Apple documentation is very short ... – Raphaël Barthomeuf Jun 18 '20 at 15:24

1 Answers1

5

I have finally found what to do to handle this situation. When I receive a .motionPaused or .motionResumed event, I have to manually add .pause and .resume events to the workout builder to make the total workout time accurate. It's not explained in Apple documentation so I hope it will help other people facing the same issue. By doing this auto pause/resume is working fine:

case .motionPaused:
            toggleSessionDisplayState(.paused)
            // manually add pause event to fix workout duration
            workoutBuilder.addWorkoutEvents([HKWorkoutEvent(type: .pause, dateInterval: DateInterval(start: Date(),duration: 0), metadata: [:])])  { (success, error) in
                if error != nil {
                    print(error!)
                }
            }
            os_log("Auto Pause Builder Event")
            
case .motionResumed:
            toggleSessionDisplayState(.running)
            // manually add resume event to fix workout duration
            workoutBuilder.addWorkoutEvents([HKWorkoutEvent(type: .resume, dateInterval: DateInterval(start: Date(),duration: 0), metadata: [:])])  { (success, error) in
                if error != nil {
                    print(error!)
                }
            }
            os_log("Auto Resume Builder Event")
  • I see in this code you're not pausing the workout session when a .motionPaused is received. Seems like you'll keep tracking data even though the app is acting like the workout is paused? – jeffbailey Dec 24 '22 at 20:13