Skip to content
AB

Building Workout Live Activities and Dynamic Island UI

Map durable workout state into ActivityKit, support interactions, and reconcile duplicate or stale activities.

Ashish BhakhandPublished

A workout Live Activity is a projection of workout state. It should not become a second source of truth.

ActivityKit separates stable attributes from changing content:

Code
struct WorkoutAttributes: ActivityAttributes {
    let workoutID: String
    let workoutName: String

    struct ContentState: Codable, Hashable {
        let startedAt: Date
        let isPaused: Bool
        let currentExercise: String?
        let completedSets: Int
    }
}

Map the persisted workout draft into this state whenever the session changes. Start an activity for active or paused sessions, update an existing match, and end it when completed or cancelled.

Reconcile on launch. If two activities exist for one workout, keep one and end extras. If the application supports only one active workout, end unrelated stale activities too.

Pause and resume App Intents must mutate the shared workout draft first, then update the Live Activity. The visible timer follows durable state rather than maintaining independent time.

Design every presentation: Lock Screen, expanded Dynamic Island, compact leading and trailing, and minimal. Missing exercise data needs a useful fallback.

Test state mapping and reconciliation as pure logic. Device testing still matters for entitlement, target membership, interaction, and dismissal behavior. Live Activities remain reliable when they mirror one durable session lifecycle.

← Back to all writing