health_connector 1.4.0 copy "health_connector: ^1.4.0" to clipboard
health_connector: ^1.4.0 copied to clipboard

A Flutter plugin to access health data from Health Connect (Android) and HealthKit (iOS)

health_connector #


📖 Overview #

health_connector provides a unified, type-safe API for accessing health data across Android and iOS platforms. It abstracts platform differences while exposing platform-specific features when needed.

✨ Features #

Feature Description
🔐 Permission Management Request/check/revoke permissions
📖 Reading Health Data Read a single health record by ID or multiple health records within a specified date/time range with pagination
✍️ Writing Health Data Write health records
🔄 Updating Health Records Modify existing record
🗑️ Deleting Health Records Remove specific records by their IDs or within a date/time range
Aggregating Health Data Sum/Avg/Min/Max Aggregation

Explore the plugin's capabilities using the Health Connector Toolbox example app:

Permission Request Read Health Data Write Health Data Aggregate Health Data

🎯 Requirements #

  • Flutter >=3.3.0
  • Dart >=3.9.2
  • Android:
    • minSdkVersion: 26 (Android 8.0)
    • compileSdk: 34+
  • iOS:
    • iOS >=15.0
    • Xcode >=14.0

🚀 Getting Started #

📦 Installation #

Add health_connector to your project:

flutter pub add health_connector

Or manually add to your pubspec.yaml:

dependencies:
  health_connector: [latest_version]

⚙️ Platform Setup #

For platform-specific setup instructions, see:

📚 Usage #

Import Package

import 'package:health_connector/health_connector.dart';

Check Platform Availability

final status = await HealthConnector.getHealthPlatformStatus();

switch (status) {
  case HealthPlatformStatus.available:
    print('Health platform ready');
    break;
  case HealthPlatformStatus.installationOrUpdateRequired:
    print('Please install or update health platform');
    break;
  case HealthPlatformStatus.unavailable:
    print('Health platform not supported');
    break;
}

Create HealthConnector Instance

final connector = await HealthConnector.create(
  HealthConnectorConfig(
    isLoggerEnabled: true, // Enable debug logging
  ),
);

// Check which platform is being used
print('Platform: ${connector.healthPlatform.name}');
// Prints: "healthConnect" on Android, "appleHealth" on iOS

Permissions

Request Permissions
final permissions = [
  HealthDataType.steps.readPermission,
  HealthDataType.steps.writePermission,
  HealthDataType.weight.readPermission,
  HealthDataType.weight.writePermission,
  // ...
];

final results = await connector.requestPermissions(permissions);

for (final result in results) {
  print('${result.permission}: ${result.status}');
}

Important: On iOS, read permissions always return PermissionStatus.unknown for privacy reasons. This prevents apps from detecting if a user has any health data.

Read Health Records

Read Health Record by ID
final recordId = HealthRecordId('existing-record-id');
final readRequest = HealthDataType.steps.readRecord(recordId);
final record = await connector.readRecord(readRequest);

if (record != null) {
  print('Steps: ${record.count.value} from ${record.startTime} to ${record.endTime}');
} else {
  print('Record not found');
}
Read Multiple Health Records
// Read step records for the last 7 days
final request = HealthDataType.steps.readRecords(
  startTime: DateTime.now().subtract(Duration(days: 7)),
  endTime: DateTime.now(),
  pageSize: 100,
);

final response = await connector.readRecords(request);

for (final record in response.records) {
  print('Steps: ${record.count.value} from ${record.startTime} to ${record.endTime}');
}
Read Multiple Health Records with Pagination
// Initialize pagination request
var request = HealthDataType.steps.readRecords(
  startTime: DateTime.now().subtract(Duration(days: 30)),
  endTime: DateTime.now(),
  pageSize: 100, // Request 100 records per page
);

var allRecords = <StepRecord>[];
var pageNumber = 1;

print('Starting pagination with pageSize: 100');

// Paginate through all records
while (true) {
  print('\n--- Page $pageNumber ---');
  
  // Fetch the current page
  final response = await connector.readRecords(request);
  
  print('Records returned: ${response.records.length}');
  print('Has nextPageRequest: ${response.nextPageRequest != null}');
  
  // Add records to our collection
  allRecords.addAll(response.records.cast<StepRecord>());
  print('Total records collected so far: ${allRecords.length}');
  
  // Platform-specific pagination handling
  if (response.nextPageRequest == null) {
    print('No nextPageRequest - pagination complete');
    break;
  }
  
  // Move to next page
  request = response.nextPageRequest!;
  pageNumber++;
}

print('\n=== Pagination Complete ===');
print('Total records fetched: ${allRecords.length}');
print('Total pages processed: $pageNumber');

Write Health Records

Write Single Health Record
final stepRecord = StepRecord(
  id: HealthRecordId.none, // Must be none for new records
  startTime: DateTime.now().subtract(Duration(hours: 1)),
  endTime: DateTime.now(),
  count: Numeric(5000),
  metadata: Metadata.automaticallyRecorded(
    device: Device.fromType(DeviceType.phone),
  ),
);

final recordId = await connector.writeRecord(stepRecord);
print('Record written with ID: $recordId');
Write Multiple Health Records
final records = [
  StepRecord(
    id: HealthRecordId.none,
    startTime: DateTime.now().subtract(Duration(hours: 2)),
    endTime: DateTime.now().subtract(Duration(hours: 1)),
    count: Numeric(3000),
    metadata: Metadata.automaticallyRecorded(
      device: Device.fromType(DeviceType.phone),
    ),
  ),
  DistanceRecord(
    id: HealthRecordId.none,
    startTime: DateTime.now().subtract(Duration(hours: 1)),
    endTime: DateTime.now(),
    distance: Length(5000),
    metadata: Metadata.automaticallyRecorded(
      device: Device.fromType(DeviceType.phone),
    ),
  ),
  // Other health records ...
];

final recordIds = await connector.writeRecords(records);
print('Wrote ${recordIds.length} records');

Update Health Records

// Read existing record
final recordId = HealthRecordId('existing-record-id');
final readRequest = HealthDataType.steps.readRecord(recordId);
final existingRecord = await connector.readRecord(readRequest);

if (existingRecord != null) {
  // Create updated record
  final updatedRecord = existingRecord.copyWith(
    startTime: existingRecord.startTime,
    endTime: existingRecord.endTime,
    count: Numeric(existingRecord.count.value + 100),
    metadata: existingRecord.metadata,
  );

  // Update returns ID (same on Android, new on iOS)
  final newId = await connector.updateRecord(updatedRecord);
  
  print('Original ID: $originalId');
  print('New ID: $newId');
  // originalId == newId on Android (originalId != newId on iOS)
}

Delete Health Records

Delete Health Records by IDs
await connector.deleteRecordsByIds(
  dataType: HealthDataType.steps,
  recordIds: [
    HealthRecordId('id-1'),
    HealthRecordId('id-2'),
  ],
);

print('Records deleted');
Delete Health Records by Date Range
await connector.deleteRecords(
  dataType: HealthDataType.steps,
  startTime: DateTime.now().subtract(Duration(days: 7)),
  endTime: DateTime.now(),
);

print('Records deleted');

Aggregate Health Data

// Get total steps for today
final sumRequest = HealthDataType.steps.aggregateSum(
  startTime: DateTime.now().startOfDay,
  endTime: DateTime.now(),
);

final sumResponse = await connector.aggregate(sumRequest);
print('Total steps today: ${sumResponse.value.value}');

// Get average weight for the last month
final avgRequest = HealthDataType.weight.aggregateAvg(
  startTime: DateTime.now().subtract(Duration(days: 30)),
  endTime: DateTime.now(),
);

final avgResponse = await connector.aggregate(avgRequest);
print('Average weight: ${avgResponse.value.inKilograms} kg');

// Get min/max weight
final minRequest = HealthDataType.weight.aggregateMin(
  startTime: DateTime.now().subtract(Duration(days: 30)),
  endTime: DateTime.now(),
);
final minResponse = await connector.aggregate(minRequest);
print('Min weight: ${minResponse.value.inKilograms} kg');

final maxRequest = HealthDataType.weight.aggregateMax(
  startTime: DateTime.now().subtract(Duration(days: 30)),
  endTime: DateTime.now(),
);
final maxResponse = await connector.aggregate(maxRequest);
print('Max weight: ${maxResponse.value.inKilograms} kg');

⚒️ Platform Specific Features #

While health_connector provides a unified API across platforms, some features are only available on specific platforms due to platform capabilities and limitations.

🤖 Android-only API #

Get All Granted Permissions

Retrieve a list of all permissions that have been granted to your app.

try {
    final grantedPermissions = await connector.getGrantedPermissions();
    print('Granted permissions: ${grantedPermissions.length}');
    
    // Iterate through granted permissions
    for (final permission in grantedPermissions) {
      print('Permission: ${permission.permission} - Status: ${permission.status}');
    }
} on HealthConnectorException catch (e) {
    if (e.errorCode == HealthConnectorErrorCode.unsupportedHealthPlatformApi) {
      print('This API is only available on Android');
    } else {
      print('Error: ${e.message}');
    }
}

Revoke All Granted Permissions

Revoke all permissions that have been granted to your app.

try {
    await connector.revokeAllPermissions();
    print('All permissions revoked successfully');
} on HealthConnectorException catch (e) {
    if (e.errorCode == HealthConnectorErrorCode.unsupportedHealthPlatformApi) {
      print('This API is only available on Android');
    } else {
      print('Error: ${e.message}');
    }
}

📋 Supported Health Data Types #

🏃 Activity #

Data Type Android iOS Documentation
Steps • Android: StepsRecord
• iOS: HKQuantityTypeIdentifier.stepCount
Distance • Android: DistanceRecord
• iOS: HKQuantityTypeIdentifier.distanceWalkingRunning
Active Calories Burned • Android: ActiveCaloriesBurnedRecord
• iOS: HKQuantityTypeIdentifier.activeEnergyBurned
Floors Climbed • Android: FloorsClimbedRecord
• iOS: HKQuantityTypeIdentifier.flightsClimbed
Wheelchair Pushes • Android: WheelchairPushesRecord
• iOS: HKQuantityTypeIdentifier.pushCount
Exercise Session / Workout • Android: ExerciseSessionRecord
• iOS: HKWorkoutTypeIdentifier
Total Calories Burned • Android: TotalCaloriesBurnedRecord
• iOS: HKQuantityTypeIdentifier.basalEnergyBurned
Cycling Pedaling Cadence • Android: CyclingPedalingCadenceRecord
• iOS: Not available
Power • Android: PowerRecord
• iOS: HKQuantityTypeIdentifier.cyclingPower
Speed • Android: SpeedRecord
• iOS: HKQuantityTypeIdentifier.walkingSpeed, HKQuantityTypeIdentifier.runningSpeed, HKQuantityTypeIdentifier.walkingSpeed, HKQuantityTypeIdentifier.runningSpeed, HKQuantityTypeIdentifier.stairAscentSpeed, HKQuantityTypeIdentifier.stairDescentSpeed
Distance Cycling • Android: Part of DistanceRecord
• iOS: HKQuantityTypeIdentifier.distanceCycling
Distance Swimming • Android: Part of DistanceRecord
• iOS: HKQuantityTypeIdentifier.distanceSwimming
Distance Wheelchair • Android: Part of DistanceRecord
• iOS: HKQuantityTypeIdentifier.distanceWheelchair
Wheelchair Distance • Android: Part of DistanceRecord
• iOS: HKQuantityTypeIdentifier.distanceWheelchair
Apple Exercise Time • Android: Not available
• iOS: HKQuantityTypeIdentifier.appleExerciseTime
Apple Stand Time • Android: Not available
• iOS: HKQuantityTypeIdentifier.appleStandTime
Nike Fuel • Android: Not available
• iOS: HKQuantityTypeIdentifier.nikeFuel
Swimming Stroke Count • Android: Not available
• iOS: HKQuantityTypeIdentifier.swimmingStrokeCount

📏 Body Measurements #

Data Type Android iOS Documentation
Weight • Android: WeightRecord
• iOS: HKQuantityTypeIdentifier.bodyMass
Height • Android: HeightRecord
• iOS: HKQuantityTypeIdentifier.height
Body Fat Percentage • Android: BodyFatRecord
• iOS: HKQuantityTypeIdentifier.bodyFatPercentage
Lean Body Mass • Android: LeanBodyMassRecord
• iOS: HKQuantityTypeIdentifier.leanBodyMass
Bone Mass • Android: BoneMassRecord
• iOS: Not available
Body Mass Index • Android: Not available
• iOS: HKQuantityTypeIdentifier.bodyMassIndex
Waist Circumference • Android: Not available
• iOS: HKQuantityTypeIdentifier.waistCircumference
Basal Metabolic Rate • Android: BasalMetabolicRateRecord
• iOS: Not available

🩸 Cycle Tracking / Reproductive Health #

Data Type Android iOS Documentation
Menstruation Flow • Android: MenstruationFlowRecord
• iOS: HKCategoryTypeIdentifier.menstrualFlow
Cervical Mucus • Android: CervicalMucusRecord
• iOS: HKCategoryTypeIdentifier.cervicalMucusQuality
Ovulation Test • Android: OvulationTestRecord
• iOS: HKCategoryTypeIdentifier.ovulationTestResult
Basal Body Temperature • Android: BasalBodyTemperatureRecord
• iOS: HKQuantityTypeIdentifier.basalBodyTemperature
Sexual Activity • Android: SexualActivityRecord
• iOS: HKCategoryTypeIdentifier.sexualActivity
Intermenstrual Bleeding • Android: Not available
• iOS: HKCategoryTypeIdentifier.intermenstrualBleeding
Pregnancy Test Result • Android: Not available
• iOS: HKCategoryTypeIdentifier.pregnancyTestResult
Progesterone Test Result • Android: Not available
• iOS: HKCategoryTypeIdentifier.progesteroneTestResult

🍎 Nutrition #

Data Type Android iOS Documentation
Hydration / Water • Android: HydrationRecord
• iOS: HKQuantityTypeIdentifier.dietaryWater
Nutrition / Dietary Energy • Android: NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietaryEnergyConsumed
Dietary Protein • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietaryProtein
Dietary Carbohydrates • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietaryCarbohydrates
Dietary Fat Total • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietaryFatTotal
Dietary Fat Saturated • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietaryFatSaturated
Dietary Fat Polyunsaturated • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietaryFatPolyunsaturated
Dietary Fat Monounsaturated • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietaryFatMonounsaturated
Dietary Cholesterol • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietaryCholesterol
Dietary Sodium • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietarySodium
Dietary Fiber • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietaryFiber
Dietary Sugar • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietarySugar
Dietary Calcium • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietaryCalcium
Dietary Iron • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietaryIron
Dietary Vitamin C • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietaryVitaminC
Dietary Vitamin D • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietaryVitaminD
Dietary Vitamin E • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietaryVitaminE
Dietary Vitamin K • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietaryVitaminK
Dietary Vitamin B6 • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietaryVitaminB6
Dietary Vitamin B12 • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietaryVitaminB12
Dietary Thiamin (B1) • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietaryThiamin
Dietary Riboflavin (B2) • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietaryRiboflavin
Dietary Niacin (B3) • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietaryNiacin
Dietary Folate • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietaryFolate
Dietary Biotin • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietaryBiotin
Dietary Pantothenic Acid • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietaryPantothenicAcid
Caffeine • Android: Part of NutritionRecord
• iOS: HKQuantityTypeIdentifier.dietaryCaffeine

😴 Sleep #

Data Type Android iOS Documentation
Sleep Session/Stage • Android: SleepSessionRecord
• iOS: HKCategoryTypeIdentifier.sleepAnalysis

❤️ Vitals #

Data Type Android iOS Documentation
Heart Rate (Series/Measurement) • Android: HeartRateSeriesRecord
• iOS: HKQuantityTypeIdentifier.heartRate
Resting Heart Rate • Android: RestingHeartRateRecord
• iOS: HKQuantityTypeIdentifier.restingHeartRate
Blood Pressure • Android: BloodPressureRecord
• iOS: HKQuantityTypeIdentifier.bloodPressureSystolic, HKQuantityTypeIdentifier.bloodPressureDiastolic
Body Temperature • Android: BodyTemperatureRecord
• iOS: HKQuantityTypeIdentifier.bodyTemperature
Oxygen Saturation • Android: OxygenSaturationRecord
• iOS: HKQuantityTypeIdentifier.oxygenSaturation
Respiratory Rate • Android: RespiratoryRateRecord
• iOS: HKQuantityTypeIdentifier.respiratoryRate
Vo2 Max • Android: Vo2MaxRecord
• iOS: HKQuantityTypeIdentifier.vo2Max
Blood Glucose • Android: BloodGlucoseRecord
• iOS: HKQuantityTypeIdentifier.bloodGlucose
Walking Heart Rate Average • Android: Not available
• iOS: HKQuantityTypeIdentifier.walkingHeartRateAverage
Heart Rate Variability SDNN • Android: Not available
• iOS: HKQuantityTypeIdentifier.heartRateVariabilitySDNN
Peripheral Perfusion Index • Android: Not available
• iOS: HKQuantityTypeIdentifier.peripheralPerfusionIndex
Blood Alcohol Content • Android: Not available
• iOS: HKQuantityTypeIdentifier.bloodAlcoholContent
Forced Vital Capacity • Android: Not available
• iOS: HKQuantityTypeIdentifier.forcedVitalCapacity
Forced Expiratory Volume • Android: Not available
• iOS: HKQuantityTypeIdentifier.forcedExpiratoryVolume1
Peak Expiratory Flow Rate • Android: Not available
• iOS: HKQuantityTypeIdentifier.peakExpiratoryFlowRate

🧘 Wellness / Mental Health #

Data Type Android iOS Documentation
Mindfulness Session • Android: MindfulnessSessionRecord
• iOS: HKCategoryTypeIdentifier.mindfulSession

🏥 Clinical Records #

Data Type Android iOS Documentation
Electrocardiogram (ECG) • Android: Not available
• iOS: HKElectrocardiogram
Vision Prescription • Android: Not available
• iOS: HKVisionPrescription

🎧 Audio Exposure #

Data Type Android iOS Documentation
Headphone Audio Exposure • Android: Not available
• iOS: HKQuantityTypeIdentifier.headphoneAudioExposureEvent
Environmental Audio Exposure • Android: Not available
• iOS: HKQuantityTypeIdentifier.environmentalAudioExposureEvent

🚶 Mobility & Gait Analysis #

Data Type Android iOS Documentation
Walking Speed • Android: Part of SpeedRecord
• iOS: HKQuantityTypeIdentifier.walkingSpeed
Running Speed • Android: Part of SpeedRecord
• iOS: HKQuantityTypeIdentifier.runningSpeed
Step Length • Android: Not available
• iOS: HKQuantityTypeIdentifier.stepLength
Walking Asymmetry Percentage • Android: Not available
• iOS: HKQuantityTypeIdentifier.walkingAsymmetryPercentage
Walking Double Support Percentage • Android: Not available
• iOS: HKQuantityTypeIdentifier.walkingDoubleSupportPercentage
Six Minute Walk Test Distance • Android: Not available
• iOS: HKQuantityTypeIdentifier.sixMinuteWalkTestDistance
Stair Ascent Speed • Android: Part of SpeedRecord
• iOS: HKQuantityTypeIdentifier.stairAscentSpeed
Stair Descent Speed • Android: Part of SpeedRecord
• iOS: HKQuantityTypeIdentifier.stairDescentSpeed

🤝 Contributing #

Contributions are welcome!

To report issues or request features, please visit our GitHub Issues.

5
likes
160
points
504
downloads

Publisher

unverified uploader

Weekly Downloads

A Flutter plugin to access health data from Health Connect (Android) and HealthKit (iOS)

Homepage
Repository (GitHub)
View/report issues

Documentation

API reference

License

Apache-2.0 (license)

Dependencies

flutter, health_connector_core, health_connector_hc_android, health_connector_hk_ios, health_connector_logger, meta

More

Packages that depend on health_connector