Workouts Write exercise sessions with an activity type, energy burned and distance using writeWorkoutData.
writeWorkoutData writes an exercise session with its activity type, time range and optional energy and distance totals. To read workouts back, see Aggregate data .
Future < bool > writeWorkoutData ({
required HealthWorkoutActivityType activityType ,
required DateTime start ,
required DateTime end ,
double ? totalEnergyBurned ,
int ? totalEnergyBurnedUnit ,
double ? totalDistance ,
int ? totalDistanceUnit ,
})
true: the workout was saved.
false: the write failed.
await health . writeWorkoutData (
activityType : HealthWorkoutActivityType . RUNNING ,
start : workoutStart ,
end : workoutEnd ,
totalDistance : 5000.0 , // 5 km in meters
totalEnergyBurned : 350.0 , // kcal
) ;
await health . writeWorkoutData (
activityType : HealthWorkoutActivityType . CYCLING ,
start : DateTime . now () . subtract ( Duration (hours : 1 )) ,
end : DateTime . now () ,
totalDistance : 15000.0 , // 15 km
totalEnergyBurned : 400.0 ,
) ;
await health . writeWorkoutData (
activityType : HealthWorkoutActivityType . SWIMMING_OPEN_WATER ,
start : workoutStart ,
end : workoutEnd ,
totalDistance : 1500.0 , // 1.5 km
totalEnergyBurned : 300.0 ,
) ;
await health . writeWorkoutData (
activityType : HealthWorkoutActivityType . TRADITIONAL_STRENGTH_TRAINING ,
start : workoutStart ,
end : workoutEnd ,
totalEnergyBurned : 200.0 ,
// No distance for strength training
) ;
await health . writeWorkoutData (
activityType : HealthWorkoutActivityType . YOGA ,
start : DateTime . now () . subtract ( Duration (minutes : 60 )) ,
end : DateTime . now () ,
totalEnergyBurned : 150.0 ,
) ;
Common HealthWorkoutActivityType values include:
WALKING, RUNNING, CYCLING, SWIMMING_OPEN_WATER, SWIMMING_POOL, HIKING, YOGA, TRADITIONAL_STRENGTH_TRAINING, FUNCTIONAL_STRENGTH_TRAINING, HIGH_INTENSITY_INTERVAL_TRAINING, DANCING, ELLIPTICAL, STAIR_CLIMBING, ROWING, SOCCER, BASKETBALL, TENNIS, GOLF, SKIING.
Many more are available. For the full list, see the HealthWorkoutActivityType enum in the API reference .
Warning
Activity types are platform-specific. The plugin validates the activity type and throws if it is not supported on the current platform.
This class records the start time, then writes the workout when it finishes:
class WorkoutSession {
final HealthWorkoutActivityType type ;
final DateTime startTime ;
DateTime ? endTime ;
double distance = 0.0 ;
double calories = 0.0 ;
WorkoutSession ({
required this . type ,
DateTime ? start ,
}) : startTime = start ?? DateTime . now () ;
void finish ({ double ? distance , double ? calories}) {
endTime = DateTime . now () ;
this . distance = distance ?? 0.0 ;
this . calories = calories ?? 0.0 ;
}
Future < bool > save ( Health health) async {
if (endTime == null ) {
throw StateError ( 'Workout not finished' ) ;
}
return await health . writeWorkoutData (
activityType : type ,
start : startTime ,
end : endTime !,
totalDistance : distance ,
totalEnergyBurned : calories ,
) ;
}
}
// Usage
final workout = WorkoutSession (
type : HealthWorkoutActivityType . RUNNING ,
) ;
// ... workout in progress ...
workout . finish (distance : 5000.0 , calories : 350.0 ) ;
final saved = await workout . save (health) ;
if (saved) {
print ( 'Workout saved!' ) ;
}
class LiveWorkoutTracker {
final Health health ;
final HealthWorkoutActivityType type ;
late DateTime startTime ;
double totalDistance = 0.0 ;
double totalCalories = 0.0 ;
LiveWorkoutTracker ({
required this . health ,
required this . type ,
}) ;
void start () {
startTime = DateTime . now () ;
print ( 'Workout started: ${ type . name } ' ) ;
}
void updateMetrics ( double distance , double calories) {
totalDistance += distance ;
totalCalories += calories ;
print ( 'Distance: ${ totalDistance } m, Calories: ${ totalCalories } ' ) ;
}
Future < bool > finish () async {
final endTime = DateTime . now () ;
final duration = endTime . difference (startTime) ;
print ( 'Workout finished: ${ duration . inMinutes } minutes' ) ;
return await health . writeWorkoutData (
activityType : type ,
start : startTime ,
end : endTime ,
totalDistance : totalDistance ,
totalEnergyBurned : totalCalories ,
) ;
}
}
// Usage
final tracker = LiveWorkoutTracker (
health : health ,
type : HealthWorkoutActivityType . RUNNING ,
) ;
tracker . start () ;
// During workout
tracker . updateMetrics ( 500.0 , 35.0 ) ; // Every 500m
tracker . updateMetrics ( 500.0 , 35.0 ) ;
// ...
final saved = await tracker . finish () ;
If energy burned was not measured, you can estimate it from MET (Metabolic Equivalent of Task) values:
double estimateCalories ({
required HealthWorkoutActivityType type ,
required Duration duration ,
required double weightKg ,
}) {
// MET values (Metabolic Equivalent of Task)
final metValues = {
HealthWorkoutActivityType . WALKING : 3.5 ,
HealthWorkoutActivityType . RUNNING : 9.8 ,
HealthWorkoutActivityType . CYCLING : 7.5 ,
HealthWorkoutActivityType . SWIMMING_OPEN_WATER : 8.0 ,
HealthWorkoutActivityType . YOGA : 2.5 ,
// Add more as needed
} ;
final met = metValues[type] ?? 5.0 ; // Default to moderate intensity
final hours = duration . inMinutes / 60.0 ;
// Calories = MET × weight (kg) × duration (hours)
return met * weightKg * hours ;
}
// Usage
final duration = workoutEnd . difference (workoutStart) ;
final estimatedCalories = estimateCalories (
type : HealthWorkoutActivityType . RUNNING ,
duration : duration ,
weightKg : 70.0 ,
) ;
await health . writeWorkoutData (
activityType : HealthWorkoutActivityType . RUNNING ,
start : workoutStart ,
end : workoutEnd ,
totalDistance : 5000.0 ,
totalEnergyBurned : estimatedCalories ,
) ;
For workouts with distinct phases, write one workout per segment:
Future < void > saveMultiSegmentWorkout () async {
final workoutStart = DateTime . now () . subtract ( Duration (hours : 1 )) ;
// Warm-up: 10 minutes walking
await health . writeWorkoutData (
activityType : HealthWorkoutActivityType . WALKING ,
start : workoutStart ,
end : workoutStart . add ( Duration (minutes : 10 )) ,
totalDistance : 800.0 ,
totalEnergyBurned : 40.0 ,
) ;
// Main workout: 30 minutes running
await health . writeWorkoutData (
activityType : HealthWorkoutActivityType . RUNNING ,
start : workoutStart . add ( Duration (minutes : 10 )) ,
end : workoutStart . add ( Duration (minutes : 40 )) ,
totalDistance : 5000.0 ,
totalEnergyBurned : 300.0 ,
) ;
// Cool-down: 10 minutes walking
await health . writeWorkoutData (
activityType : HealthWorkoutActivityType . WALKING ,
start : workoutStart . add ( Duration (minutes : 40 )) ,
end : workoutStart . add ( Duration (minutes : 50 )) ,
totalDistance : 600.0 ,
totalEnergyBurned : 30.0 ,
) ;
}
Future < bool > writeValidatedWorkout ({
required HealthWorkoutActivityType type ,
required DateTime start ,
required DateTime end ,
double ? distance ,
double ? calories ,
}) async {
// Validate duration
final duration = end . difference (start) ;
if (duration . isNegative || duration . inSeconds < 60 ) {
print ( 'Invalid workout duration' ) ;
return false ;
}
// Validate distance
if (distance != null && distance < 0 ) {
print ( 'Invalid distance' ) ;
return false ;
}
// Validate calories
if (calories != null && (calories < 0 || calories > 10000 )) {
print ( 'Invalid calorie value' ) ;
return false ;
}
return await health . writeWorkoutData (
activityType : type ,
start : start ,
end : end ,
totalDistance : distance ,
totalEnergyBurned : calories ,
) ;
}
Android iOS
Activity types are mapped to Health Connect exercise types.
Some iOS-specific types may not have an exact Android equivalent.
Requires the Health Connect SDK.
Other apps may not display all workout details.
Supports all HealthWorkoutActivityType values.
Workouts appear in the Apple Fitness app.
Can include route data (requires a separate API).
Heart rate is associated automatically if available.