health

v13.3.1

Wrapper for Apple's HealthKit on iOS and Google's Health Connect on Android.

Package archive: https://pubdev.letsnova.ru/api/archives/health/13.3.1.tar.gz

Installdart pub add health

Readme

Health

Enables reading and writing health data from/to Apple Health and Google Health Connect.

NOTE: Google has deprecated the Google Fit API. According to the documentation, as of May 1st 2024 developers cannot sign up for using the API. As such, this package has removed support for Google Fit as of version 11.0.0 and users are urged to upgrade as soon as possible.

The plugin supports:

  • handling permissions to access health data using the hasPermissions, requestAuthorization, revokePermissions methods.
  • reading health data using the getHealthDataFromTypes method.
  • writing health data using the writeHealthData method.
  • writing workouts using the writeWorkout method.
  • writing workout routes on iOS and Android using the startWorkoutRoute / insertWorkoutRouteData / finishWorkoutRoute methods.
  • writing meals on iOS (Apple Health) & Android using the writeMeal method.
  • writing audiograms on iOS using the writeAudiogram method.
  • writing blood pressure data using the writeBloodPressure method.
  • accessing total step counts using the getTotalStepsInInterval method.
  • cleaning up duplicate data points via the removeDuplicates method.
  • removing data of a given type in a selected period of time using the delete method.

Note that for Android, the target phone needs to have the Health Connect app installed (which is currently in beta) and have access to the internet.

See the tables below for supported health and workout data types.

Setup

Apple Health (iOS)

First, add the following 2 entries to the Info.plist:

<key>NSHealthShareUsageDescription</key>
                <string>We will sync your data with the Apple Health app to give you better insights</string>
                <key>NSHealthUpdateUsageDescription</key>
                <string>We will sync your data with the Apple Health app to give you better insights</string>
                

Then, open your Flutter project in Xcode by right clicking on the "ios" folder and selecting "Open in Xcode". Next, enable "HealthKit" by adding a capability inside the "Signing & Capabilities" tab of the Runner target's settings.

Google Health Connect (Android)

Health Connect requires the following lines in the AndroidManifest.xml file (see also the example app):

<!-- Check whether Health Connect is installed or not -->
                <queries>
                  <package android:name="com.google.android.apps.healthdata" />
                  <intent>
                    <action android:name="androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE" />
                  </intent>
                </queries>
                

In the Health Connect permissions activity there is a link to your privacy policy. You need to grant the Health Connect app access in order to link back to your privacy policy. In the example below, you should either replace .MainActivity with an activity that presents the privacy policy or have the Main Activity route the user to the policy. This step may be required to pass Google app review when requesting access to sensitive permissions.

<activity-alias
                     android:name="ViewPermissionUsageActivity"
                     android:exported="true"
                     android:targetActivity=".MainActivity"
                     android:permission="android.permission.START_VIEW_PERMISSION_USAGE">
                        <intent-filter>
                            <action android:name="android.intent.action.VIEW_PERMISSION_USAGE" />
                            <category android:name="android.intent.category.HEALTH_PERMISSIONS" />
                        </intent-filter>
                </activity-alias>
                

For each data type you want to access, the READ and WRITE permissions need to be added to the AndroidManifest.xml file. The list of permissions can be found here on the data types page.

An example of asking for permission to read and write heart rate data is shown below and more examples can also be found in the example app.

<uses-permission android:name="android.permission.health.READ_HEART_RATE"/>
                <uses-permission android:name="android.permission.health.WRITE_HEART_RATE"/>
                

If you plan to read or write Activity Intensity records (the HealthDataType.ACTIVITY_INTENSITY type), be sure to add the corresponding Health Connect permissions introduced with that data type:

<uses-permission android:name="android.permission.health.READ_ACTIVITY_INTENSITY"/>
                <uses-permission android:name="android.permission.health.WRITE_ACTIVITY_INTENSITY"/>
                

By default, Health Connect restricts read data to 30 days from when permission has been granted.

You can check and request access to historical data using the isHealthDataHistoryAuthorized and requestHealthDataHistoryAuthorization methods, respectively.

The above methods require the following permission to be declared:

<uses-permission android:name="android.permission.health.READ_HEALTH_DATA_HISTORY"/>
                

Accessing fitness data (e.g. Steps) requires permission to access the "Activity Recognition" API. To set it add the following line to your AndroidManifest.xml file.

<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/>
                

Additionally, for workouts, if the distance of a workout is requested then the location permissions below are needed.

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
                <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
                

Because this is labeled as a dangerous protection level, the permission system will not grant it automatically and it requires the user's action. You can prompt the user for it using the permission_handler plugin. Follow the plugin setup instructions and add the following line before requesting the data:

await Permission.activityRecognition.request();
                await Permission.location.request();
                

Finally, an intent-filter needs to be added to the .MainActivity activity.

<activity
                  android:name=".MainActivity"
                  android:exported="true"
                
                  ....
                
                  <!-- Intention to show Permissions screen for Health Connect API -->
                  <intent-filter>
                    <action android:name="androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE" />
                  </intent-filter>
                </activity>
                

There's a debug, main and profile version which are chosen depending on how you start your app. In general, it's sufficient to add permission only to the main version.

Android 14

This plugin uses the new registerForActivityResult when requesting permissions from Health Connect. In order for that to work, the Main app's activity should extend FlutterFragmentActivity instead of FlutterActivity. This adjustment allows casting from Activity to ComponentActivity for accessing registerForActivityResult.

In your MainActivity.kt file, update the MainActivity class so that it extends FlutterFragmentActivity instead of the default FlutterActivity:

...
                import io.flutter.embedding.android.FlutterFragmentActivity
                ...
                
                class MainActivity: FlutterFragmentActivity() {
                ...
                }
                

Android X

Replace the content of the android/gradle.properties file with the following lines:

org.gradle.jvmargs=-Xmx1536M
                android.enableJetifier=true
                android.useAndroidX=true
                

Usage

See the example app for detailed examples of how to use the Health API.

A instance of the Health plugin is create using the Health() constructor and is subsequently configured calling the configure method. Once configured, the plugin can be used for handling permissions and getting and adding data to Apple Health or Google Health Connect. Below is a simplified flow of how to use the plugin.


                  // Global Health instance
                  final health = Health();
                
                  // configure the health plugin before use.
                  await health.configure();
                
                
                  // define the types to get
                  var types = [
                    HealthDataType.STEPS,
                    HealthDataType.BLOOD_GLUCOSE,
                  ];
                
                  // requesting access to the data types before reading them
                  bool requested = await health.requestAuthorization(types);
                
                  var now = DateTime.now();
                
                  // fetch health data from the last 24 hours
                  List<HealthDataPoint> healthData = await health.getHealthDataFromTypes(
                     now.subtract(Duration(days: 1)), now, types);
                
                  // request permissions to write steps and blood glucose
                  types = [HealthDataType.STEPS, HealthDataType.BLOOD_GLUCOSE];
                  var permissions = [
                      HealthDataAccess.READ_WRITE,
                      HealthDataAccess.READ_WRITE
                  ];
                  await health.requestAuthorization(types, permissions: permissions);
                
                  // write steps and blood glucose
                  bool success = await health.writeHealthData(10, HealthDataType.STEPS, now, now);
                  success = await health.writeHealthData(3.1, HealthDataType.BLOOD_GLUCOSE, now, now);
                
                  // you can also specify the recording method to store in the metadata (default is RecordingMethod.automatic)
                  // on iOS only `RecordingMethod.automatic` and `RecordingMethod.manual` are supported
                  // Android additionally supports `RecordingMethod.active` and `RecordingMethod.unknown`
                  success &= await health.writeHealthData(10, HealthDataType.STEPS, now, now, recordingMethod: RecordingMethod.manual);
                
                  // get the number of steps for today
                  var midnight = DateTime(now.year, now.month, now.day);
                  int? steps = await health.getTotalStepsInInterval(midnight, now);
                

Writing workout routes (iOS & Android)

  1. Request share/read permissions for both HealthDataType.WORKOUT and HealthDataType.WORKOUT_ROUTE, and ensure location permissions are granted (iOS: Core Location permissions; Android: ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION).
  2. When the workout session starts, open a builder with final builderId = await health.startWorkoutRoute();.
  3. Collect GPS samples using CLLocationManager (or an equivalent service) and periodically push ordered batches of WorkoutRouteLocation values via insertWorkoutRouteData.
  4. Save the workout itself (for example, with writeWorkoutData) and capture the resulting HealthKit workout UUID.
  5. Call finishWorkoutRoute(builderId: builderId, workoutUuid: workoutUuid, metadata: {...}) to commit the route, or discardWorkoutRoute(builderId) if the session is cancelled.

Health Connect note: Android only surfaces routes while your app is in the foreground, and other apps' routes may return a ConsentRequired flag. Today (Health Connect 1.1.0) the system does not expose the ExerciseRouteRequestContract documented by Google, so the only way to read third-party routes is to have the user manually grant "Always allow" for Exercise routes inside the Health Connect app (Health Connect → App permissions → Your app → Exercise routes). Also remember to declare the following permissions in your Android manifest:

  • <uses-permission android:name="android.permission.health.READ_EXERCISE_ROUTE"/>
  • <uses-permission android:name="android.permission.health.WRITE_EXERCISE_ROUTE"/>
  • <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> (or ACCESS_COARSE_LOCATION)

Health Data

A HealthDataPoint object contains the following data fields:

String uuid;
                HealthValue value;
                HealthDataType type;
                HealthDataUnit unit;
                DateTime dateFrom;
                DateTime dateTo;
                HealthPlatformType sourcePlatform;
                String sourceDeviceId;
                String sourceId;
                String sourceName;
                RecordingMethod recordingMethod;
                WorkoutSummary? workoutSummary;
                

where a HealthValue can be any type of AudiogramHealthValue, ElectrocardiogramHealthValue, ElectrocardiogramVoltageValue, NumericHealthValue, NutritionHealthValue, or WorkoutHealthValue.

A HealthDataPoint object can be serialized to and from JSON using the toJson() and fromJson() methods. JSON serialization is using camel_case notation. Null values are not serialized. For example;

{
                  "value": {
                    "__type": "NumericHealthValue",
                    "numeric_value": 141.0
                  },
                  "type": "STEPS",
                  "unit": "COUNT",
                  "date_from": "2024-04-03T10:06:57.736",
                  "date_to": "2024-04-03T10:12:51.724",
                  "source_platform": "appleHealth",
                  "source_device_id": "F74938B9-C011-4DE4-AA5E-CF41B60B96E7",
                  "source_id": "com.apple.health.81AE7156-EC05-47E3-AC93-2D6F65C717DF",
                  "source_name": "iPhone12.bardram.net",
                  "recording_method": 3
                  "value": {
                    "__type": "NumericHealthValue",
                    "numeric_value": 141.0
                  },
                  "type": "STEPS",
                  "unit": "COUNT",
                  "date_from": "2024-04-03T10:06:57.736",
                  "date_to": "2024-04-03T10:12:51.724",
                  "source_platform": "appleHealth",
                  "source_device_id": "F74938B9-C011-4DE4-AA5E-CF41B60B96E7",
                  "source_id": "com.apple.health.81AE7156-EC05-47E3-AC93-2D6F65C717DF",
                  "source_name": "iPhone12.bardram.net",
                  "recording_method": 2
                }
                

Fetch health data

See the example app for a showcasing of how it's done.

Note On iOS the device must be unlocked before health data can be requested. Otherwise an error will be thrown:

flutter: Health Plugin Error:
                flutter:  PlatformException(FlutterHealth, Results are null, Optional(Error Domain=com.apple.healthkit Code=6 "Protected health data is inaccessible" UserInfo={NSLocalizedDescription=Protected health data is inaccessible}))
                

Fetch single health data by UUID

In order to retrieve a single record, it is required to provide String uuid and HealthDataType type.

Please see example below:

HealthDataPoint? healthPoint = await health.getHealthDataByUUID(
                  uuid: 'random-uuid-string',
                  type: HealthDataType.STEPS,
                );
                
I/FLUTTER_HEALTH( 9161): Success: {uuid=random-uuid-string, value=12, date_from=1742259061009, date_to=1742259092888, source_id=, source_name=com.google.android.apps.fitness, recording_method=0}
                

Assuming that the uuid and type are coming from your database.

Filtering by recording method

Google Health Connect and Apple HealthKit both provide ways to distinguish samples collected "automatically" and manually entered data by the user.

As such, when fetching data you have the option to filter the fetched data by recording method as such:

List<HealthDataPoint> healthData = await health.getHealthDataFromTypes(
                  types: types,
                  startTime: yesterday,
                  endTime: now,
                  recordingMethodsToFilter: [RecordingMethod.manual, RecordingMethod.unknown],
                );
                

Note that for this to work, the information needs to have been provided when writing the data to Health Connect or Apple Health. For example, steps added manually through the Apple Health App will set HKWasUserEntered to true (corresponding to RecordingMethod.manual), however it seems that adding steps manually to Google Fit does not write the data with the RecordingMethod.manual in the metadata, instead it shows up as RecordingMethod.unknown. This is an open issue, and as such filtering manual entries when querying step count on Android with getTotalStepsInInterval(includeManualEntries: false) does not necessarily filter out manual steps.

NOTE: On iOS, you can only filter by RecordingMethod.automatic and RecordingMethod.manual as it is stored HKMetadataKeyWasUserEntered is a boolean value in the metadata.

Filtering out duplicates

If the same data is requested multiple times and saved in the same array duplicates will occur.

A single data point can be compared to each other with the == operator, i.e.

HealthDataPoint p1 = ...;
                HealthDataPoint p2 = ...;
                bool same = p1 == p2;
                

If you have a list of data points, duplicates can be removed with:

List<HealthDataPoint> points = ...;
                points = health.removeDuplicates(points);
                

Android: Reading Health Data in Background

Currently health connect allows apps to read health data in the background. In order to achieve this add the following permission to your AndroidManifest.XML:

<!-- For reading data in background -->
                <uses-permission android:name="android.permission.health.READ_HEALTH_DATA_IN_BACKGROUND"/>
                

Furthermore, the plugin now exposes three new functions to help you check and request access to read data in the background:

  1. isHealthDataInBackgroundAvailable(): Checks if the Health Data in Background feature is available
  2. isHealthDataInBackgroundAuthorized(): Checks the current status of the Health Data in Background permission
  3. requestHealthDataInBackgroundAuthorization(): Requests the Health Data in Background permission.

Fetch single health data by UUID

In order to retrieve a single record, it is required to provide String uuid and HealthDataType type.

Please see example below:

HealthDataPoint? healthPoint = await health.getHealthDataByUUID(
                  uuid: 'E9F2EEAD-8FC5-4CE5-9FF5-7C4E535FB8B8',
                  type: HealthDataType.WORKOUT,
                );
                
data by UUID: HealthDataPoint -
                    uuid: E9F2EEAD-8FC5-4CE5-9FF5-7C4E535FB8B8,
                    value: WorkoutHealthValue - workoutActivityType: RUNNING,
                           totalEnergyBurned: null,
                           totalEnergyBurnedUnit: KILOCALORIE,
                           totalDistance: 2400,
                           totalDistanceUnit: METER
                           totalSteps: null,
                           totalStepsUnit: null,
                    unit: NO_UNIT,
                    dateFrom: 2025-05-02 07:31:00.000,
                    dateTo: 2025-05-02 08:25:00.000,
                    dataType: WORKOUT,
                    platform: HealthPlatformType.appleHealth,
                    deviceId: unknown,
                    sourceId: com.apple.Health,
                    sourceName: Health
                    recordingMethod: RecordingMethod.manual
                    workoutSummary: WorkoutSummary - workoutType: runningtotalDistance: 2400, totalEnergyBurned: 0, totalSteps: 0
                    metadata: null
                    deviceModel: null
                

Assuming that the uuid and type are coming from your database.

Data Types

The plugin supports the following HealthDataType.

Data Type Unit Apple Health Google Health Connect Comments
ACTIVE_ENERGY_BURNED CALORIES yes yes
ATRIAL_FIBRILLATION_BURDEN PERCENTAGE yes
BASAL_ENERGY_BURNED CALORIES yes yes
BLOOD_GLUCOSE MILLIGRAM_PER_DECILITER yes yes
BLOOD_OXYGEN PERCENTAGE yes yes
BLOOD_PRESSURE_DIASTOLIC MILLIMETER_OF_MERCURY yes yes
BLOOD_PRESSURE_SYSTOLIC MILLIMETER_OF_MERCURY yes yes
BODY_FAT_PERCENTAGE PERCENTAGE yes yes
BODY_MASS_INDEX NO_UNIT yes yes
BODY_TEMPERATURE DEGREE_CELSIUS yes yes
BODY_WATER_MASS KILOGRAMS yes
ELECTRODERMAL_ACTIVITY SIEMENS yes
HEART_RATE BEATS_PER_MINUTE yes yes
HEIGHT METERS yes yes
RESTING_HEART_RATE BEATS_PER_MINUTE yes yes
RESPIRATORY_RATE RESPIRATIONS_PER_MINUTE yes yes
PERIPHERAL_PERFUSION_INDEX PERCENTAGE yes
STEPS COUNT yes yes
WAIST_CIRCUMFERENCE METERS yes
WALKING_HEART_RATE BEATS_PER_MINUTE yes
WEIGHT KILOGRAMS yes yes
DISTANCE_WALKING_RUNNING METERS yes
FLIGHTS_CLIMBED COUNT yes yes
DISTANCE_DELTA METERS yes
MINDFULNESS MINUTES yes
SLEEP_ASLEEP MINUTES yes yes on iOS, this refers to asleepUnspecified, and on Android this refers to STAGE_TYPE_SLEEPING (asleep but specific stage is unknown)
SLEEP_AWAKE MINUTES yes yes
SLEEP_AWAKE_IN_BED MINUTES yes
SLEEP_DEEP MINUTES yes yes
SLEEP_IN_BED MINUTES yes
SLEEP_LIGHT MINUTES yes yes on iOS, this refers to asleepCore
SLEEP_OUT_OF_BED MINUTES yes
SLEEP_REM MINUTES yes yes
SLEEP_UNKNOWN MINUTES yes
SLEEP_SESSION MINUTES yes
WATER LITER yes yes
EXERCISE_TIME MINUTES yes
WORKOUT NO_UNIT yes yes See table below
WORKOUT_ROUTE NO_UNIT yes yes iOS 11+ and Android (as Exercise Route); use the workout route builder APIs described in the Writing workout routes section above.
HIGH_HEART_RATE_EVENT NO_UNIT yes Requires Apple Watch to write the data
LOW_HEART_RATE_EVENT NO_UNIT yes Requires Apple Watch to write the data
IRREGULAR_HEART_RATE_EVENT NO_UNIT yes Requires Apple Watch to write the data
HEART_RATE_VARIABILITY_RMSSD MILLISECONDS yes
HEART_RATE_VARIABILITY_SDNN MILLISECONDS yes Requires Apple Watch to write the data
HEADACHE_NOT_PRESENT MINUTES yes
HEADACHE_MILD MINUTES yes
HEADACHE_MODERATE MINUTES yes
HEADACHE_SEVERE MINUTES yes
HEADACHE_UNSPECIFIED MINUTES yes
AUDIOGRAM DECIBEL_HEARING_LEVEL yes
ELECTROCARDIOGRAM VOLT yes Requires Apple Watch to write the data
NUTRITION NO_UNIT yes yes
INSULIN_DELIVERY INTERNATIONAL_UNIT yes
MENSTRUATION_FLOW NO_UNIT yes yes
WATER_TEMPERATURE DEGREE_CELSIUS yes Related to/Requires Apple Watch Ultra's Underwater Diving Workout
SLEEP_WRIST_TEMPERATURE DEGREE_CELSIUS yes READ Only - appleSleepingWristTemperature
SKIN_TEMPERATURE DEGREE_CELSIUS yes Must check health connect for availability
UNDERWATER_DEPTH METER yes Related to/Requires Apple Watch Ultra's Underwater Diving Workout
UV_INDEX COUNT yes
LEAN_BODY_MASS KILOGRAMS yes yes
WALKING_SPEED METER_PER_SECOND yes (yes) On Android this will be recorded as SPEED with similar unit
APPLE_MOVE_TIME SECOND yes READ Only
APPLE_STAND_HOUR HOUR yes READ Only
APPLE_MOVE_TIME SECOND yes READ Only

Workout Types

The plugin supports the following HealthWorkoutActivityType.

Workout Type Apple Health Google Health Connect Comments
AMERICAN_FOOTBALL yes yes
ARCHERY yes
AUSTRALIAN_FOOTBALL yes yes
BADMINTON yes yes
BARRE yes
BASEBALL yes yes
BASKETBALL yes yes
BIKING yes yes on iOS this is CYCLING, but name changed here to fit with Android
BOWLING yes
BOXING yes yes
CALISTHENICS yes
CARDIO_DANCE yes (yes) on Android this will be stored as DANCING
CLIMBING yes
COOLDOWN yes
CORE_TRAINING yes
CRICKET yes yes
CROSS_COUNTRY_SKIING yes (yes) on Android this will be stored as SKIING
CROSS_TRAINING yes
CURLING yes
DANCING yes yes on iOS this is DANCE, but name changed here to fit with Android
DISC_SPORTS yes
DOWNHILL_SKIING yes (yes) on Android this will be stored as SKIING
ELLIPTICAL yes yes
EQUESTRIAN_SPORTS yes
FENCING yes yes
FISHING yes
FITNESS_GAMING yes
FLEXIBILITY yes
FRISBEE_DISC yes
FUNCTIONAL_STRENGTH_TRAINING yes (yes) on Android this will be stored as STRENGTH_TRAINING
GOLF yes yes
GUIDED_BREATHING yes
GYMNASTICS yes yes
HAND_CYCLING yes
HANDBALL yes yes
HIGH_INTENSITY_INTERVAL_TRAINING yes yes
HIKING yes yes
HOCKEY yes
HUNTING yes
JUMP_ROPE yes
KICKBOXING yes
LACROSSE yes
MARTIAL_ARTS yes yes
MIND_AND_BODY yes
MIXED_CARDIO yes
PADDLE_SPORTS yes
PARAGLIDING yes
PICKLEBALL yes
PILATES yes yes
PLAY yes
PREPARATION_AND_RECOVERY yes
RACQUETBALL yes yes
ROCK_CLIMBING (yes) yes on iOS this will be stored as CLIMBING
ROWING yes yes
RUGBY yes yes
RUNNING yes yes
RUNNING_TREADMILL (yes) yes on iOS this will be stored as RUNNING
SAILING yes yes
SCUBA_DIVING yes
SKATING yes yes On iOS this will be stored as SKATING_SPORTS
SKIING (yes) yes on iOS you have to choose between CROSS_COUNTRY_SKIING and DOWNHILL_SKIING
SNOW_SPORTS yes
SNOWBOARDING yes yes
SOCCER yes
SOCIAL_DANCE yes (yes) on Android this will be stored as DANCING
SOFTBALL yes yes
SQUASH yes yes
STAIR_CLIMBING yes yes
STAIR_CLIMBING_MACHINE yes
STAIRS yes
STEP_TRAINING yes
STRENGTH_TRAINING (yes) yes on iOS you have to choose between FUNCTIONAL_STRENGTH_TRAINING or TRADITIONAL_STRENGTH_TRAINING
SURFING yes yes on iOS this is SURFING_SPORTS, but name changed here to fit with Android
SWIMMING yes (yes) on Android you have to choose between SWIMMING_OPEN_WATER and SWIMMING_POOL
SWIMMING_OPEN_WATER (yes) yes on iOS this will be stored as SWIMMING
SWIMMING_POOL (yes) yes on iOS this will be stored as SWIMMING
TABLE_TENNIS yes yes
TAI_CHI yes
TENNIS yes yes
TRACK_AND_FIELD yes
TRADITIONAL_STRENGTH_TRAINING yes (yes) on Android this will be stored as STRENGTH_TRAINING
UNDERWATER_DIVING yes
VOLLEYBALL yes yes
WALKING yes yes
WATER_FITNESS yes
WATER_POLO yes yes
WATER_SPORTS yes
WEIGHTLIFTING yes
WHEELCHAIR (yes) yes on iOS you have to choose between WHEELCHAIR_RUN_PACE or WHEELCHAIR_WALK_PACE
WHEELCHAIR_RUN_PACE yes (yes) on Android this will be stored as WHEELCHAIR
WHEELCHAIR_WALK_PACE yes (yes) on Android this will be stored as WHEELCHAIR
WRESTLING yes
YOGA yes yes
OTHER yes yes

License

This software is copyright (c) the Technical University of Denmark (DTU) and is part of the Copenhagen Research Platform. This software is available 'as-is' under a MIT license.

Changelog

13.3.1

  • iOS: Fix issues with app crashing on iOS 15
  • iOS: Add support for AppleSleepingWristTemperature - PR #468
  • Android: Add support for SkinTemperatureRecord (READ/WRITE)

13.3.0

  • Add support for WORKOUT_ROUTE - PR #454
  • Android: Add support for ActivityIntensityRecord (READ/WRITE/Aggregate)
  • Update to androidx.health.connect:connect-client:1.2.0-alpha02

13.2.1

No changes - Now the Health package lives in its own repository at https://github.com/carp-dk/carp-health-flutter

13.2.0

  • Add get health data by UUID (see getHealthDataByUUID()) - PR #1193, #1194
  • Add delete by UUID (deleteByUUID())
  • Add support for unit conversion in WeightRecord, HeightRecord, BodyTemperatureRecord, and BloodGlucoseRecord - PR #1212
  • Update compileSDK to 36 - Fix #1261
  • Update Gradle to 8.9.1
  • Update org.jetbrains.kotlin.android to 2.1.0
  • Update androidx.health.connect:connect-client to 1.1.0-rc03
  • Update device_info_plus to 12.1.0 - Fix #1264

13.1.4

  • Fix adding mindfulness resulted in crash in iOS
  • Support SPM for iOS

13.1.3

  • Fix permissions issues with iOS
  • Fix #1231

13.1.2

13.1.1

  • Fix #1207 - (Important: Some property names might have changed compared to before for Nutrition)
  • Fix #1201
  • iOS: Add APPLE_STAND_TIME, APPLE_STAND_HOUR, and APPLE_MOVE_TIME health data types (READ ONLY) #1190

13.1.0

  • Refactored Android native implementation (No Flutter API changes)
  • Android: Add SPEED health data type - PR #1183
  • iOS: Add WALKING_SPEED health data type - PR #1183
  • Add METER_PER_SECOND health data unit

13.0.1

  • Refactored Swift native implementation - See PR #1175 and #1208 for more information:
SwiftHealthPlugin (Main Plugin Class)
                ├── HealthDataReader (Reading health data)
                ├── HealthDataWriter (Writing health data)
                ├── HealthDataOperations (Permissions and deletion)
                ├── HealthUtilities (Helper functions)
                └── HealthConstants (Constants and enums)
                

13.0.0

  • Refactored Swift native implementation

12.2.1

  • iOS: Add swift_version for add-to-app implementations - PR #1205

12.2.0

  • iOS: Add deviceModel in returned Health data to identify the device that generated the data of the receiver. (in iOS source_name represents the revision of the source responsible for saving the receiver.)
  • Android: Add read health data in background - PR #1184
  • Fix #1169 where meal_type property in Nutrition was null always
  • iOS: Add CARDIO_DANCE HealthDataType - #1146

12.1.0

  • Add delete record by UUID method. See function deleteByUUID(required String uuid, HealthDataType? type)
  • iOS: Parse metadata to remove unsupported types - PR #1120
  • iOS: Add UV Index Types
  • Android: Add request access to historic data #1126 - PR #1127
<!-- Add the following permission into AndroidManifest.xml -->
                <uses-permission android:name="android.permission.health.READ_HEALTH_DATA_HISTORY"/>
                
  • Android:
    • Update androidx.compose:compose-bom to 2025.02.00
    • Update androidx.health.connect:connect-client to 1.1.0-alpha11
    • Update androidx.fragment:fragment-ktx to 1.8.6
    • Update to Java 11
  • Update example apps

12.0.1

  • Update of API and README doc
  • Fix #1118

12.0.0

  • BREAKING This release introduces a significant architectural change to the health plugin by removing the singleton pattern.

    • Dependency Injection for DeviceInfoPlugin:
    • The Health class is no longer a singleton.
    • The Health() factory constructor is removed.
    • The Health class now accepts an (optional) DeviceInfoPlugin dependency through its constructor, this change was introduced to provide easy mocking of the DeviceInfo class during unit tests.
    • This architectural change means that, for the application to work correctly, the Health class MUST be initialized correctly as a global instance.
    • Impact:
      • For most users, no immediate code changes are required but it is paramount to initialize the Health class as a global instance (i.e. do not call Health() every time but rather define an instance final health = Health();).
  • BREAKING (Android) Remove automatic permission request of DISTANCE_DELTA and TOTAL_CALORIES_BURNED data types when requesting permission for WORKOUT health data type.

    • For WORKOUTs that require above permissions, now those need to be requested manually.
    • Fix #984 - PR #1055
  • Add LEAN_BODY_MASS data type #1078 - PR #1097

    • The following AndroidManifest values are required to READ/WRITE LEAN_BODY_MASS:
    <uses-permission android:name="android.permission.health.READ_LEAN_BODY_MASS"/>
                    <uses-permission android:name="android.permission.health.WRITE_LEAN_BODY_MASS"/>
                    
  • iOS: Add WATER_TEMPERATURE and UNDERWATER_DEPTH health values #1096

  • iOS: Add support for Underwater Diving workout #1096

  • Fix #1072 and #1074

  • Fix issue where iOS delete not deleting own records - PR #1104

  • Fix #950 - PR #1103

  • Fix #1047 and #939 - PR #1091

  • Fix issue where SLEEP_LIGHT type was not aligned correctly - PR #1086

  • Fix #1051 - PR #1052

  • Updated intl to ^0.20.1 #1092

  • Updated device_info_plus to ^11.2.0

  • Example app: Updated permission_handler to ^11.3.1

11.1.1

11.1.0

  • Fix of #1043
  • Type-safe JSON deserialization using carp_serializable v. 2.0

11.0.0

  • BREAKING Remove Google Fit support in the Android code, as well as Google FIt related dependencies and references throughout the documentation
    • Remove useHealthConnectIfAvailable from the parameters of Health().configure()
    • Remove the disconnect method which was previously used to disconnect from Google Fit.
    • Remove the flowRate value from writeBloodOxygen as this is not supported by Health Connect.
    • Remove support for various HealthWorkoutActivityTypes which were supported by Google Fit. Some of these do not have suitable alternatives in Google Health Connect (and are not supported on iOS). The list of removed types can be found in PR #1014
  • BREAKING introduce a new RecordingMethod enum
    • This can be used to filter records by automatic or manual entries when fetching data
    • You can also specify the recording method to write in the metadata
    • Remove isManualEntry from HealthDataPoint in favor of recordingMethod, of which the value is an enum RecordingMethod
    • Remove includeManualEntry (previously a boolean) from some of the querying methods in favor of recordingMethodsToFilter.
    • For complete details on relevant changes, see the description of PR #1023
  • Add support for all sleep stages across iOS and Android
    • Clean up relevant documentation
    • Remove undocumented sleep stages
    • BREAKING certain sleep stages were removed/combined into other related stages see PR #1026 for the complete list of changes and a discussion of the motivation in issue #985
  • Android: Add support for OTHER workout type
  • Cleaned up workout activity types for consistency across iOS and Android, see PR #1020 for a complete list of changes
  • iOS: add support for menstruation flow, PR #1008
  • Android: Add support for heart rate variability, PR #1009
  • iOS: add support for atrial fibrillation burden, PR #1031
  • Add support for UUIDs in health records for both HealthKit and Health Connect, PR #1019
  • Fix an issue when querying workouts, the native code could respond with an activity that is not supported in the Health package, causing an error - this will fallback to HealthWorkoutActivityType.other - PR #1016
  • Remove deprecated Android v1 embeddings, PR #1021

10.2.0

  • Using named parameters in most methods for consistency.
  • Added a HealthPlatformType to save which health platform the data originates from (Apple Health, Google Fit, or Google Health Connect).
  • Android: Improved support for Google Health Connect
    • getHealthConnectSdkStatus, PR #941
    • installHealthConnect, PR #943
    • workout title, PR #938
  • iOS: Add support for saving blood pressure as a correlation, PR #919

10.1.1

  • Fix of error in WorkoutSummary JSON serialization.
  • Fix of #934
  • Empty value check for calories nutrition, PR #926

10.0.0

  • BREAKING The plugin now works as a singleton using Health() to access it (instead of creating an instance of HealthFactory).
    • This entails that the plugin now need to be configured using the configure() method before use.
    • The example app has been update to demonstrate this new singleton model.
  • Support for new data types:
    • body water mass, PR #917
    • caffeine, PR #924
    • workout summary, manual entry and new health data types, PR #920
  • Fixed SleepSessionRecord, PR #928
  • Update to API and README docs
  • Upgrade to Dart 3.2 and Flutter 3.
  • Added Dart linter and fixed a series of type casting issues.
  • Using carp_serializable for consistent camel_case and type-safe generation of JSON serialization methods for polymorphic health data type classes.

9.0.0

  • Updated HC to comply with Android 14, PR #834 and #882
  • Added checks for NullPointerException, closes issue #878
  • Updated intl to ^0.19.0
  • Upgrade to AGP 8, PR #868
  • Added missing google fit workout types, PR #836
  • Added pagination in HC, PR #862
  • Fix of permission in example app + improvements to doc, PR #875

8.1.0

  • Fixed sleep stages on iOS, Issue #803
  • Added Nutrition data type, includes PR #679
  • Lowered minSDK, Issue #809

8.0.0

  • Fixed issue #774, #779
  • Merged PR #579, #717, #770
  • Upgraded to mavenCentral, upgraded minSDK, compileSDK, targetSDK
  • Updated health connect client to 1.1.0
  • Added respiratory rate and peripheral perfusion index to HealthConnect
  • Minor fixes to requestAuthorization, sleep stage filtering

7.0.1

  • Updated dart doc

7.0.0

  • Merged PR #722
  • Added deep, light, REM, and out of bed sleep to iOS and Android HealthConnect

6.0.0

  • Fixed issues #694, #696, #697, #698
  • added totalSteps for HealthConnect
  • added supplemental oxygen flow rate for blood oxygen saturation on Android

5.0.0

  • Added initial support for the new Health Connect API, as Google Fit is being deprecated.
    • Does not yet support revokePermissions, getTotalStepsInInterval.
  • Changed Intl package version dependency to ^0.17.0 to work with flutter stable version.
  • Updated the example app to handle more buttons.

4.6.0

  • Added method for revoking permissions. On Android it uses disableFit() to remove access to Google Fit - revokePermissions. Documented lack of methods for iOS.

4.5.0

  • Updated android sdk, gradle
  • Updated enumToString to native .name
  • Update and fixed JSON serialization of HealthDataPoints
  • Removed auth request in writeWorkoutData to avoid bug when denying the auth.
  • Merged pull requests #653, #652, #639, #644, #668
  • Further developed #644 on android to accommodate having the writeBloodPressure api.
  • Small bug fixes

4.4.0

4.3.0

  • upgrade to device_info_plus: ^8.0.0

4.2.0

  • upgrade to device_info_plus: ^7.0.0

4.1.1

4.1.0

  • update of device_info_plus: ^4.0.0
  • upgraded to Dart 2.17 and Flutter 3.0

4.0.0

  • Large refactor of the HealthDataPoint value into generic HealthValue and added NumericHealthValue, AudiogramHealthValue and WorkoutHealthValue
  • Added support for Audiograms with writeAudiogram and in getHealthDataFromTypes
  • Added support for Workouts with writeWorkout and in getHealthDataFromTypes
  • Added all HealthWorkoutActivityTypes
  • Added more HealthDataUnit types
  • Fix of #432
  • updated documentation in code
  • updated documentation in README.md
  • updated example app
  • cleaned up code
  • removed requestPermissions as it was essentially a duplicate of requestAuthorization

3.4.4

  • Fix of #500.
  • Added Headache-types to HealthDataTypes on iOS

3.4.3

3.4.2

  • Resolved concurrent issues with native threads PR#483.
  • HealthKit CategorySample PR#485.
  • update of API documentation.

3.4.0

  • Add sleep in bed to android PR#457.
  • Add the android.permission.ACTIVITY_RECOGNITION setup to the README PR#458.
  • Fixed (regression) issues with metric and permissions PR#462.
  • Get total steps PR#471.
  • update of example app to reflect new features.
  • update of API documentation.

3.3.1

  • DISTANCE_DELTA is for Android, not iOS PR#428.
  • added missing READ_ACCESS PR#454.

3.3.0

  • Write support on Google Fit and HealthKit PR#430.

3.2.1

  • Updated device_info_plus version dependency

3.2.0

  • added simple HKWorkout and ExerciseTime support PR#421.

3.1.1+1

  • added functions to request authorization PR#394

3.1.0

  • added sleep data to Android + fix of permissions and initialization PR#372
  • testability of HealthDataPoint PR#388.
  • update to using the device_info_plus plugin

3.0.6

  • Added two new fields to the HealthDataPoint - SourceId and SourceName and populate when data is read. This allows data points to be disambiguous and in some cases allows us to get more accurate data. For example the number of steps can be reported from Apple Health and Watch and without source data they are aggregated into just "steps" producing an inaccurate result PR#281.

3.0.5

  • Null safety in Dart has been implemented
  • The plugin supports the Android v2 embedding

3.0.4

  • Upgrade to device_info version 2.0.0

3.0.3

  • Merged various PRs, mostly smaller fixes

3.0.2

  • Upgrade to device_info version 1.0.0

3.0.1+1

3.0.0

  • Changed the flow for requesting access and reading data
    • Access must be requested manually before reading
    • This simplifies the data flow and makes it easier to reason about when debugging
  • Data read access is no longer checked for each individual type, but rather on the set of types specified.

2.0.9

  • Now handles the case when asking for BMI on Android when no height data has been collected.

2.0.8

  • Fixed a merge issue which had deleted the data types added in 2.0.4.

2.0.7

2.0.6

2.0.5

  • Now uses 'device_info' rather than 'device_id' for getting device information

2.0.4+1

  • Static analysis, formatting etc.

2.0.4

  • Added Sleep data, Water, and Mindfulness.

2.0.3

  • The method requestAuthorization is now public again.

2.0.2

  • Updated the API to take a list of types rather than a single type, when requesting health data.

2.0.1+1

  • Removed the need for try-catch on the programmer's end

2.0.1

  • Removed UUID and instead introduced a comparison operator

2.0.0

  • Changed the API substantially to allow for granular Data Type permissions

1.1.6

Added the following Health Types as per PR #147

  • DISTANCE_WALKING_RUNNING
  • FLIGHTS_CLIMBED
  • MOVE_MINUTES
  • DISTANCE_DELTA

1.1.5

1.1.4

  • Corrected table of units

1.1.3

  • Updated table with units

1.1.2

  • Now supports the data type HEART_RATE_VARIABILITY_SDNN on iOS

1.1.1

1.1.0

  • Introduced UUID to the HealthDataPoint class
  • Re-did the example application

1.0.6

  • Fixed a null-check warning in the obj-c code (issue #87)

1.0.5

  • Updated gradle-wrapper distribution url gradle-5.4.1-all.zip
  • Updated docs

1.0.2

  • Updated documentation for Android and Google Fit.

1.0.1

  • Streamlined DataType units in Flutter.