health_connector
Unified, type-safe health data access for Flutter β a single API to read, write, delete, and aggregate health metrics across iOS HealthKit and Android Health Connect.
π Table of Contents
Getting Started
- π― Requirements
- π¦ Installation
- β‘ Quick Start
- π Exploring SDK using Health Connector Toolbox
- π Core Concepts
Features
- βοΈ Feature Management
- π Permission Management
- π Reading Health Data
- βοΈ Writing Health Data
- π Updating Health Records
- ποΈ Deleting Health Records
- β Aggregating Health Data
Additional Information
Reference
Resources
π― Requirements
| Platform | Minimum Version | Notes |
|---|---|---|
| Android | API 26+ | Requires Health Connect app |
| iOS | β₯15.0 |
π¦ Installation
Step 1: Add the Package
flutter pub add health_connector
Or add manually to pubspec.yaml:
dependencies:
health_connector: ^1.4.0
Step 2: Platform Setup
π€ Android Health Connect Setup
Update AndroidManifest.xml
Add to android/app/src/main/AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<!-- Your existing configuration -->
<!-- Health Connect intent filter for showing permissions rationale -->
<activity-alias
android:name="ViewPermissionUsageActivity"
android:exported="true"
android:targetActivity=".MainActivity"
android:permission="android.permission.START_VIEW_PERMISSION_USAGE">
<intent-filter>
<action android:name="androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE" />
</intent-filter>
</activity-alias>
</application>
<!-- Declare Health Connect permissions for each data type you use -->
<!-- Read permissions -->
<uses-permission android:name="android.permission.health.READ_STEPS" />
<uses-permission android:name="android.permission.health.READ_WEIGHT" />
<uses-permission android:name="android.permission.health.READ_HEART_RATE" />
<!-- Write permissions -->
<uses-permission android:name="android.permission.health.WRITE_STEPS" />
<uses-permission android:name="android.permission.health.WRITE_WEIGHT" />
<uses-permission android:name="android.permission.health.WRITE_HEART_RATE" />
<!-- Feature permissions -->
<uses-permission android:name="android.permission.health.READ_HEALTH_DATA_IN_BACKGROUND" />
<uses-permission android:name="android.permission.health.READ_HEALTH_DATA_HISTORY" />
</manifest>
Important: You must declare a permission for each health data type and feature your app accesses. See the Health Connect permissions list for all available permissions.
π iOS HealthKit Setup
Enable HealthKit Capability
- Open your project in Xcode (
ios/Runner.xcworkspace) - Select your app target
- Go to Signing & Capabilities tab
- Click + Capability
- Add HealthKit
Update Info.plist
Add to ios/Runner/Info.plist:
<dict>
<!-- Existing keys -->
<!-- Required: Describe why your app reads health data -->
<key>NSHealthShareUsageDescription</key>
<string>This app needs to read your health data to provide personalized insights.</string>
<!-- Required: Describe why your app writes health data -->
<key>NSHealthUpdateUsageDescription</key>
<string>This app needs to save health data to track your progress.</string>
</dict>
Warning: Vague or generic usage descriptions may result in App Store rejection. Be specific about what data you access and why.
β‘ Quick Start
Get health data flowing in under 5 minutes:
import 'package:health_connector/health_connector.dart';
Future<void> quickStart() async {
// 1. Check platform availability
final status = await HealthConnector.getHealthPlatformStatus();
if (status != HealthPlatformStatus.available) {
print('Health platform not available: $status');
return;
}
// 2. Create connector instance
final connector = await HealthConnector.create(
HealthConnectorConfig(isLoggerEnabled: true),
);
// 3. Request permissions for steps
final results = await connector.requestPermissions([
HealthDataType.steps.readPermission,
HealthDataType.steps.writePermission,
]);
// 4. Check if write permission was granted
final writeGranted = results.any((r) =>
r.permission == HealthDataType.steps.writePermission &&
r.status == PermissionStatus.granted);
if (!writeGranted) {
print('Write permission not granted');
return;
}
// 5. Read today's step records
final response = await connector.readRecords(
HealthDataType.steps.readInTimeRange(
startTime: DateTime.now().subtract(Duration(days: 1)),
endTime: DateTime.now(),
),
);
for (final record in response.records) {
print('Steps: ${record.count.value} (${record.startTime} - ${record.endTime})');
}
// 6. Write a new step record
final newRecord = StepsRecord(
id: HealthRecordId.none, // Always use .none for new records
startTime: DateTime.now().subtract(Duration(hours: 1)),
endTime: DateTime.now(),
count: Numeric(1500),
metadata: Metadata.automaticallyRecorded(
device: Device.fromType(DeviceType.phone),
),
);
try {
final recordId = await connector.writeRecord(newRecord);
print('Record written with ID: $recordId');
} on NotAuthorizedException catch (e) {
print('Permission denied: ${e.message}');
} on HealthConnectorException catch (e) {
print('Error: ${e.message}');
}
}
π Exploring the SDK Features with Health Connector Toolbox
| Permission Request | Read Data | Write Data | Delete Data | Aggregate Data |
|---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
To explore the SDK's capabilities hands-on, you can use the Health Connector Toolbox example app included in the repository. The toolbox app was created to showcase the SDK's features and is used internally for manual testing purposes.
Note: The toolbox is intended as a demonstration and testing tool only. It is not recommended as a reference for building production applications.
What the Toolbox Offers
- Interactive demonstrations of core SDK features
- Permission management UI examples
- Read, write, update, and delete operations
- Data aggregation examples
- Visual representation of health records
Running the Toolbox
# Clone the repository
git clone https://github.com/fam-tung-lam/health_connector.git
cd health_connector
# Navigate to the toolbox app
cd examples/health_connector_toolbox
# Install dependencies
flutter pub get
# Run on your device
flutter run
π Core Concepts
Architecture
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Your Flutter App β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β health_connector β
β (Unified cross-platform API) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
βΌ βΌ
βββββββββββββββββββββββββββ βββββββββββββββββββββββββββββββ
β health_connector_hk_ios β β health_connector_hc_android β
β (Apple HealthKit) β β (Android Health Connect) β
βββββββββββββββββββββββββββ βββββββββββββββββββββββββββββββ
Key Types
| Type | Description |
|---|---|
HealthConnector |
Main entry point for all health data operations |
HealthDataType |
Enumeration of supported metrics (steps, weight, etc.) |
HealthRecord |
Base class for all health data records |
Permission |
Base class for data and feature permission types |
Request/Response |
Request/Response objects for read/aggregate/delete operations |
HealthConnectorConfig |
Configuration options (logging, etc.) |
Request-Response Pattern
The SDK uses a request-response pattern for read, aggregate, and delete operations. This design abstracts the significant API differences between Health Connect and HealthKit, providing you with a consistent interface regardless of the underlying platform.
How It Works
Instead of calling methods directly with raw parameters, you create strongly-typed request objects
through the HealthDataType class:
// Reading records: Create request via HealthDataType
final readRequest = HealthDataType.steps.readInTimeRange(
startTime: DateTime.now().subtract(Duration(days: 7)),
endTime: DateTime.now(),
);
final response = await connector.readRecords(readRequest);
// Aggregating data: Create request via HealthDataType
final aggregateRequest = HealthDataType.steps.aggregateSum(
startTime: DateTime.now().subtract(Duration(days: 1)),
endTime: DateTime.now(),
);
final aggregateResponse = await connector.aggregate(aggregateRequest);
// Deleting records: Create request via HealthDataType
final deleteRequest = HealthDataType.steps.deleteByIds([recordId]);
await connector.deleteRecords(deleteRequest);
Why This Pattern?
Health Connect and HealthKit have fundamentally different APIs.
The request-response pattern solves this by:
- Encapsulating platform logic β The SDK translates your request into the appropriate platform-specific API calls
- Type safety β Each
HealthDataTypeonly exposes the operations it supports (e.g.,aggregateSum()is only available on types that support sum aggregation) - Validation β Requests validate parameters at creation time, catching errors early
Write and Update Operations
Write and update operations do not use the request-response pattern. This is because:
- Write operations have consistent APIs across both platforms β both accept health record objects
- Update operations are only supported on Android Health Connect, because iOS HealthKit uses the immutable data model.
Type-Safe Generics
The SDK leverages Dart generics to provide compile-time type safety. Each HealthDataType is
parameterized with its corresponding HealthRecord type and MeasurementUnit, ensuring the correct
types flow through all operations automatically.
// HealthDataType.weight is defined as `HealthDataType<WeightRecord, Mass>`
// This means:
// - Read operations return `WeightRecord` (not a generic `HealthRecord`)
// - Aggregation returns `Mass` (the measurement unit for weight)
// The compiler automatically infers the correct record type
final request = HealthDataType.weight.readInTimeRange(
startTime: start,
endTime: end,
);
// request is `ReadRecordsInTimeRangeRequest<WeightRecord>`
final response = await connector.readRecords(request);
// response.records is `List<WeightRecord>`, not `List<HealthRecord>`
// You can directly access `WeightRecord`-specific properties without casting
for (final record in response.records) {
print('Steps: ${record.weight.value}'); // β
No cast needed
}
// Same for aggregation - the measurement unit is inferred
final avgRequest = HealthDataType.weight.aggregateAvg(
startTime: start,
endTime: end,
);
// `avgRequest` is `AggregateRequest<WeightRecord, Mass>`
final avgWeight = await connector.aggregate(avgRequest);
// `avgWeight` is `Mass`, not `MeasurementUnit`
print('Total steps: ${total.value}'); // β
Correct type automatically
This generic approach means:
- No runtime type casting β The compiler knows the exact record and unit types
- IDE autocompletion β Your IDE suggests the correct properties for each record type
- Compile-time errors β Type mismatches are caught before your app runs
π§βπ» Usage
βοΈ Feature Management
Platform features (such as background health data reading) have different availability characteristics across platforms.
Platform Differences
iOS HealthKit
- All features are available and granted by default
- When checking feature status with
getFeatureStatus(), the SDK always returnsHealthPlatformFeatureStatus.available - When requesting feature permissions with
requestPermissions(), the SDK always returnsPermissionStatus.granted - No additional user action is required for feature access
Android Health Connect
- Feature availability depends on Android version and Health Connect SDK version
- Some features require specific minimum versions, f.e. background health data reading requires
Health Connect SDK
v1.1.0-alpha04 - Feature status must be checked before requesting permissions
Checking Feature Availability
// Check if background reading is available
final status = await connector.getFeatureStatus(
HealthPlatformFeature.readHealthDataInBackground,
);
if (status == HealthPlatformFeatureStatus.available) {
// Feature is supported - safe to request permission
await connector.requestPermissions([
HealthPlatformFeature.readHealthDataInBackground.permission,
]);
} else {
// Feature not available on this device/version
print('Background reading not available');
// Implement fallback or disable feature in UI
}
Feature Permission Status
When checking the status of a feature permission:
final permissionStatus = await connector.getPermissionStatus(
HealthPlatformFeature.readHealthDataInBackground.permission,
);
// On iOS: Always returns PermissionStatus.granted
// On Android: Returns actual status (granted/denied)
π Permission Management
Request Permissions
iOS Privacy Note: Read permissions always return
PermissionStatus.unknownon iOS. This is intentionalβApple prevents apps from detecting whether users have health data by checking permission status.
final permissions = [
// Data permissions
HealthDataType.steps.readPermission,
HealthDataType.steps.writePermission,
HealthDataType.weight.readPermission,
HealthDataType.weight.writePermission,
// Feature permissions
HealthPlatformFeature.readHealthDataInBackground.permission,
];
final results = await connector.requestPermissions(permissions);
for (final result in results) {
print('${result.permission}: ${result.status}');
}
Check Individual Permission Status
final status = await connector.getPermissionStatus(
HealthDataType.steps.readPermission,
);
switch (status) {
case PermissionStatus.granted:
print('Permission granted');
case PermissionStatus.denied:
print('Permission denied');
case PermissionStatus.unknown:
print('Cannot determine (iOS read permission)');
}
Get All Granted Permissions (Android Health Connect Only)
iOS Privacy Note: This API is not available on iOS. HealthKit does not provide a way to query all granted permissions to protect user privacy. Apps cannot enumerate what health data access they have been granted.
try {
final grantedPermissions = await connector.getGrantedPermissions();
for (final permission in grantedPermissions) {
if (permission is HealthDataPermission) {
print('${permission.dataType} (${permission.accessType})');
}
}
} on UnsupportedOperationException {
print('Only available on Android');
}
Revoke All Permissions (Android Health Connect Only)
iOS Privacy Note: This API is not available on iOS. HealthKit requires users to manually revoke permissions through the iOS Settings app. This ensures users have full control and visibility over their health data permissions.
try {
await connector.revokeAllPermissions();
} on UnsupportedOperationException {
print('Only available on Android');
}
π Reading Health Data
Platform Note - Historical Data Access:
Android Health Connect
By default, Health Connect only provides access to the last 30 days of historical health data. To read data older than 30 days, theHealthPlatformFeature.readHealthDataHistoryfeature must be available and its permission must be granted.iOS HealthKit
HealthKit has no default limitation on historical data access. Apps can read health data from any time period, subject only to user permission.
Read by ID
final recordId = HealthRecordId('existing-record-id');
final request = HealthDataType.steps.readRecord(recordId);
final record = await connector.readRecord(request);
if (record != null) {
print('Steps: ${record.count.value}');
} else {
print('Record not found');
}
Read Multiple Records
final request = HealthDataType.steps.readInTimeRange(
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} (${record.startTime} - ${record.endTime})');
}
Pagination
var request = HealthDataType.steps.readInTimeRange(
startTime: DateTime.now().subtract(Duration(days: 30)),
endTime: DateTime.now(),
pageSize: 100,
);
final allRecords = <StepsRecord>[];
while (true) {
final response = await connector.readRecords(request);
allRecords.addAll(response.records.cast<StepsRecord>());
if (response.nextPageRequest == null) break;
request = response.nextPageRequest!;
}
print('Total records: ${allRecords.length}');
βοΈ Writing Health Data
Write Single Record
final stepRecord = StepsRecord(
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 ID: $recordId');
Atomic Write Multiple Records
All records succeed or all fail together:
final records = [
StepsRecord(
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),
),
),
StepsRecord(
id: HealthRecordId.none,
startTime: DateTime.now().subtract(Duration(hours: 1)),
endTime: DateTime.now(),
count: Numeric(2000),
metadata: Metadata.automaticallyRecorded(
device: Device.fromType(DeviceType.phone),
),
),
];
final recordIds = await connector.writeRecords(records);
print('Wrote ${recordIds.length} records');
π Updating Health Records
iOS Privacy Note: HealthKit does not provide an update API because it uses an immutable data model. Once a health record is written to HealthKit, it cannot be modifiedβonly deleted.
Update Record (Android Health Connect Only)
final recordId = HealthRecordId('existing-record-id');
final request = HealthDataType.steps.readRecord(recordId);
final existingRecord = await connector.readRecord(request);
if (existingRecord != null) {
final updatedRecord = existingRecord.copyWith(
count: Numeric(existingRecord.count.value + 500),
);
await connector.updateRecord(updatedRecord);
print('Record updated');
}
Atomic Update Multiple Records (Android Health Connect Only)
Update multiple records atomicallyβall succeed or all fail together:
// Read existing records
final readRequest = HealthDataType.steps.readInTimeRange(
startTime: DateTime.now().subtract(Duration(days: 7)),
endTime: DateTime.now(),
);
final response = await connector.readRecords(readRequest);
// Update all records by adding 100 steps to each
final updatedRecords = response.records.map((record) {
return record.copyWith(
count: Numeric(record.count.value + 100),
);
}).toList();
// Batch update all records
await connector.updateRecords(updatedRecords);
print('Updated ${updatedRecords.length} records');
iOS HealthKit Update Workaround (Delete + Write)
// 1. Delete existing record
await connector.deleteRecords(
HealthDataType.steps.deleteByIds([existingRecord.id]),
);
// 2. Write new record with updated values
final newRecord = StepsRecord(
id: HealthRecordId.none,
startTime: existingRecord.startTime,
endTime: existingRecord.endTime,
count: Numeric(newValue),
metadata: existingRecord.metadata,
);
final newId = await connector.writeRecord(newRecord);
// Note: newId will be different from the original ID
ποΈ Deleting Health Records
Atomic Delete by IDs
await connector.deleteRecords(
HealthDataType.steps.deleteByIds([
HealthRecordId('id-1'),
HealthRecordId('id-2'),
]),
);
Atomic Delete by Time Range
await connector.deleteRecords(
HealthDataType.steps.deleteInTimeRange(
startTime: DateTime.now().subtract(Duration(days: 7)),
endTime: DateTime.now(),
),
);
Important: Apps can only delete records they created. Attempting to delete records from other apps will silently fail.
β Aggregating Health Data
Sum Aggregation
Get the total value over a period, such as total steps for a day:
final sumRequest = HealthDataType.steps.aggregateSum(
startTime: DateTime.now().subtract(Duration(days: 1)),
endTime: DateTime.now(),
);
final sumResponse = await connector.aggregate(sumRequest);
print('Total steps: ${sumResponse.value.value}');
Average Aggregation
Get the average value over 30 days:
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');
Minimum Aggregation
Get the minimum recorded value over a period:
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');
Maximum Aggregation
Get the maximum recorded value over a period:
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');
π― Real-World Use Cases
Fitness Tracker
Track daily activity with steps, calories, and distance:
Future<Map<String, double>> getDailyActivitySummary(
HealthConnector connector,
DateTime date,
) async {
final startOfDay = DateTime(date.year, date.month, date.day);
final endOfDay = startOfDay.add(Duration(days: 1));
final steps = await connector.aggregate(
HealthDataType.steps.aggregateSum(
startTime: startOfDay,
endTime: endOfDay,
),
);
final calories = await connector.aggregate(
HealthDataType.activeCaloriesBurned.aggregateSum(
startTime: startOfDay,
endTime: endOfDay,
),
);
return {
'steps': steps.value.value,
'calories': calories.value.inKilocalories,
};
}
Health Dashboard
Display vital signs with recent measurements:
Future<void> displayVitals(HealthConnector connector) async {
final now = DateTime.now();
final weekAgo = now.subtract(Duration(days: 7));
// Get latest weight
final weightResponse = await connector.readRecords(
HealthDataType.weight.readInTimeRange(
startTime: weekAgo,
endTime: now,
pageSize: 1,
),
);
if (weightResponse.records.isNotEmpty) {
final latestWeight = weightResponse.records.first as WeightRecord;
print('Latest weight: ${latestWeight.weight.inKilograms} kg');
}
// Get heart rate average
final heartRateAvg = await connector.aggregate(
HealthDataType.restingHeartRate.aggregateAvg(
startTime: weekAgo,
endTime: now,
),
);
print('Avg resting HR: ${heartRateAvg.value.inBeatsPerMinute} bpm');
}
Nutrition Logger
Log meals with macronutrients:
Future<void> logMeal({
required HealthConnector connector,
required String mealName,
required double calories,
required double proteinGrams,
required double carbsGrams,
required double fatGrams,
}) async {
final now = DateTime.now();
final nutritionRecord = NutritionRecord(
id: HealthRecordId.none,
startTime: now.subtract(Duration(minutes: 30)),
endTime: now,
mealType: MealType.lunch,
name: mealName,
energy: Energy.kilocalories(calories),
protein: Mass.grams(proteinGrams),
totalCarbohydrate: Mass.grams(carbsGrams),
totalFat: Mass.grams(fatGrams),
metadata: Metadata.manual(),
);
await connector.writeRecord(nutritionRecord);
print('Meal logged: $mealName');
}
π API Reference
HealthConnector Methods
| Method | Description | Android Health Connect | iOS HealthKit | Accepts | Returns | Throws |
|---|---|---|---|---|---|---|
create([config]) |
Creates a new connector instance | β | β | HealthConnectorConfig? |
Future<HealthConnector> |
|
getHealthPlatformStatus() |
Checks if health platform is available | β | β | Future<HealthPlatformStatus> |
||
requestPermissions(permissions) |
Requests health data permissions | β | β | List<Permission> |
Future<List<PermissionRequestResult>> |
|
getPermissionStatus(permission) |
Checks status of a single permission | β | β | Permission |
Future<PermissionStatus> |
|
getGrantedPermissions() |
Returns all granted permissions | β | β (strict privacy model) | Future<List<Permission>> |
|
|
revokeAllPermissions() |
Revokes all permissions | β | β (strict privacy model) | Future<void> |
|
|
getFeatureStatus(feature) |
Checks if a platform feature is available | β | β | HealthPlatformFeature |
Future<HealthPlatformFeatureStatus> |
|
readRecord(request) |
Reads a single record by ID | β | β | ReadRecordByIdRequest<HealthRecord> |
Future<HealthRecord?> |
|
readRecords(request) |
Reads records in a time range | β | β | ReadRecordsInTimeRangeRequest<HealthRecord> |
Future<ReadRecordsInTimeRangeResponse<HealthRecord>> |
|
writeRecord(record) |
Writes a single health record | β | β | HealthRecord |
Future<HealthRecordId> |
|
writeRecords(records) |
Writes multiple records atomically | β | β | List<HealthRecord> |
Future<List<HealthRecordId>> |
|
updateRecord(record) |
Updates an existing record | β | β (immutable data model) | HealthRecord |
Future<void> |
|
updateRecords(records) |
Batch updates records | β | β (immutable data model) | List<HealthRecord> |
Future<void> |
|
deleteRecords(request) |
Deletes records by ID or time range | β | β | DeleteRecordsRequest<HealthRecord> |
Future<void> |
|
aggregate(request) |
Aggregates health data (sum, avg, min, max) | β | β | AggregateRequest<HealthRecord, MeasurementUnit> |
Future<MeasurementUnit> |
|
β οΈ Error Handling
The plugin provides two approaches for handling errors:
Approach 1: Catching Specific Exceptions
Use Dart's type-based exception handling to catch specific error types.
try {
await connector.requestPermissions([...]);
await connector.writeRecord(record);
} on NotAuthorizedException catch (e) {
// User denied or revoked permissions
// Recovery: Explain why permission is needed, guide to settings
print('Permission denied: ${e.message}');
} on InvalidConfigurationException catch (e) {
// Missing AndroidManifest.xml or Info.plist configuration
// Recovery: Fix app configuration (development-time error)
print('Configuration error: ${e.message}');
} on UnsupportedOperationException catch (e) {
// Platform doesn't support this operation
// Recovery: Check platform before calling, use alternative approach
print('Not supported: ${e.message}');
} on InvalidArgumentException catch (e) {
// Invalid input (e.g., startTime > endTime, negative values)
// Recovery: Validate inputs before calling
print('Invalid argument: ${e.message}');
} on HealthPlatformUnavailableException catch (e) {
// Device doesn't support health API
// Recovery: Disable health features for this device
print('Health unavailable: ${e.message}');
} on HealthPlatformNotInstalledOrUpdateRequiredException catch (e) {
// Health Connect needs installation/update (Android Health Connect Only)
// Recovery: Prompt user to install/update Health Connect
print('Health Connect needs update: ${e.message}');
} on RemoteErrorException catch (e) {
// Transient I/O or communication error
// Recovery: Retry with exponential backoff
print('Remote error: ${e.message}');
} on HealthConnectorException catch (e) {
// Generic fallback for unexpected errors
print('Unknown error [${e.code}]: ${e.message}');
}
Approach 2: Handling by Error Code
Catch the base HealthConnectorException and switch on HealthConnectorErrorCode.
try {
await connector.requestPermissions([...]);
await connector.writeRecord(record);
} on HealthConnectorException catch (e) {
switch (e.code) {
case HealthConnectorErrorCode.notAuthorized:
print('Permission denied: ${e.message}');
case HealthConnectorErrorCode.invalidConfiguration:
print('Configuration error: ${e.message}');
case HealthConnectorErrorCode.unsupportedOperation:
print('Not supported: ${e.message}');
case HealthConnectorErrorCode.invalidArgument:
print('Invalid argument: ${e.message}');
case HealthConnectorErrorCode.healthPlatformUnavailable:
print('Health unavailable: ${e.message}');
case HealthConnectorErrorCode.healthPlatformNotInstalledOrUpdateRequired:
print('Health Connect needs update: ${e.message}');
case HealthConnectorErrorCode.remoteError:
print('Remote error: ${e.message}');
case HealthConnectorErrorCode.unknown:
print('Unknown error [${e.code}]: ${e.message}');
}
}
Exception Quick Reference
| Exception | Platform | Cause | Recovery |
|---|---|---|---|
NotAuthorizedException |
Both | Permission denied/revoked | Guide user to settings |
InvalidConfigurationException |
Both | Missing manifest entries | Fix configuration |
UnsupportedOperationException |
Both | API not available | Check platform first |
InvalidArgumentException |
Both | Invalid input values | Validate inputs |
HealthPlatformUnavailableException |
Both | Device unsupported | Disable health features |
HealthPlatformNotInstalledOrUpdateRequiredException |
Android Health Connect | Health Connect missing | Prompt installation |
π§ Troubleshooting
Common Issues
| Issue | Platform | Solution |
|---|---|---|
HealthPlatformUnavailableException |
iOS HealthKit | Add HealthKit capability in Xcode β Signing & Capabilities |
HealthPlatformUnavailableException |
Android Health Connect | Device doesn't support Health Connect (requires Android 8.0+) |
HealthPlatformNotInstalledOrUpdateRequiredException |
Android Health Connect | Prompt user to install Health Connect |
InvalidConfigurationException |
Android Health Connect | Add required permissions to AndroidManifest.xml |
InvalidConfigurationException |
iOS HealthKit | Add NSHealthShareUsageDescription and NSHealthUpdateUsageDescription to Info.plist |
Read permissions return unknown |
iOS HealthKit | Normal behaviorβiOS doesn't expose read permission status for privacy |
| Can't delete/update records | Both | Apps can only modify records they created |
Debug Logging
Enable detailed logs to troubleshoot issues:
final connector = await HealthConnector.create(
HealthConnectorConfig(isLoggerEnabled: true),
);
β FAQ
Why do iOS read permissions always return unknown?
Apple intentionally hides read permission status to protect user privacy. This prevents apps from inferring whether a user has any health data by checking if read permission was denied.
How do I handle Health Connect not being installed?
final status = await HealthConnector.getHealthPlatformStatus();
if (status == HealthPlatformStatus.installationOrUpdateRequired) {
// Show dialog prompting user to install Health Connect
// Open Play Store: https://play.google.com/store/apps/details?id=com.google.android.apps.healthdata
}
What's the difference between heartRateSeriesRecord and heartRateMeasurementRecord?
- Android Health Connect: Uses
heartRateSeriesRecordβa single record with multiple samples over a time interval - iOS HealthKit: Uses
heartRateMeasurementRecordβeach measurement is a separate record with its own ID
Can I read health data from other apps?
Yes, with user permission. When granted read access, you can read health data from all sources (other apps, devices, manual entries).
Can I delete health data from other apps?
No. Apps can only delete records they created. This is a platform security restriction.
π Supported Health Data Types
π Activity
| Data Type | Description | Android Health Connect | iOS HealthKit | SDK Data Type | Aggregation |
|---|---|---|---|---|---|
| Steps | Number of steps taken | StepsRecord | HKQuantityTypeIdentifier.stepCount | StepsHealthDataType<StepsRecord, Number> |
Sum |
| Distance (generic) | Generic distance traveled | DistanceRecord | β | DistanceHealthDataType<DistanceRecord, Length> |
Sum |
| Active Calories Burned | Energy burned through active movement | ActiveCaloriesBurnedRecord | HKQuantityTypeIdentifier.activeEnergyBurned | ActiveCaloriesBurnedHealthDataType<ActiveCaloriesBurnedRecord, Energy> |
Sum |
| Floors Climbed | Number of floors (flights of stairs) climbed | FloorsClimbedRecord | HKQuantityTypeIdentifier.flightsClimbed | FloorsClimbedHealthDataType<FloorsClimbedRecord, Number> |
Sum |
| Wheelchair Pushes | Number of wheelchair pushes | WheelchairPushesRecord | HKQuantityTypeIdentifier.pushCount | WheelchairPushesHealthDataType<WheelchairPushesRecord, Number> |
Sum |
π Distance Types
| Data Type | Description | Android Health Connect | iOS HealthKit | SDK Data Type | Aggregation |
|---|---|---|---|---|---|
| Distance (generic) | Generic distance traveled | DistanceRecord | β | DistanceHealthDataType<DistanceRecord, Length> |
Sum |
| Walking/Running Distance | Distance covered by walking or running | β | HKQuantityTypeIdentifier.distanceWalkingRunning | WalkingRunningDistanceHealthDataType<WalkingRunningDistanceRecord, Length> |
Sum |
| Cycling Distance | Distance covered by cycling | β | HKQuantityTypeIdentifier.distanceCycling | CyclingDistanceHealthDataType<CyclingDistanceRecord, Length> |
Sum |
| Swimming Distance | Distance covered by swimming | β | HKQuantityTypeIdentifier.distanceSwimming | SwimmingDistanceHealthDataType<SwimmingDistanceRecord, Length> |
Sum |
| Wheelchair Distance | Distance covered using a wheelchair | β | HKQuantityTypeIdentifier.distanceWheelchair | WheelchairDistanceHealthDataType<WheelchairDistanceRecord, Length> |
Sum |
| Downhill Snow Sports Distance | Distance covered during downhill snow sports | β | HKQuantityTypeIdentifier.distanceDownhillSnowSports | DownhillSnowSportsDistanceHealthDataType<DownhillSnowSportsDistanceRecord, Length> |
Sum |
| Cross Country Skiing Distance | Distance covered during cross country skiing | β | HKQuantityTypeIdentifier.distanceCrossCountrySkiing | CrossCountrySkiingDistanceDataType<CrossCountrySkiingDistanceRecord, Length> |
Sum |
| Paddle Sports Distance | Distance covered during paddle sports | β | HKQuantityTypeIdentifier.distancePaddleSports | PaddleSportsDistanceDataType<PaddleSportsDistanceRecord, Length> |
Sum |
| Rowing Distance | Distance covered during rowing | β | HKQuantityTypeIdentifier.distanceRowing | RowingDistanceDataType<RowingDistanceRecord, Length> |
Sum |
| Skating Sports Distance | Distance covered during skating sports | β | HKQuantityTypeIdentifier.distanceSkatingSports | SkatingSportsDistanceDataType<SkatingSportsDistanceRecord, Length> |
Sum |
| Six Minute Walk Test Distance | Distance covered during 6-minute walk test | β | HKQuantityTypeIdentifier.sixMinuteWalkTestDistance | SixMinuteWalkTestDistanceDataType<SixMinuteWalkTestDistanceRecord, Length> |
Sum |
π Body Measurements
| Data Type | Description | Android Health Connect | iOS HealthKit | SDK Data Type | Aggregation |
|---|---|---|---|---|---|
| Weight | Body weight measurement | WeightRecord | HKQuantityTypeIdentifier.bodyMass | WeightHealthDataType<WeightRecord, Mass> |
Avg, Min, Max |
| Height | Body height measurement | HeightRecord | HKQuantityTypeIdentifier.height | HeightHealthDataType<HeightRecord, Length> |
Avg, Min, Max |
| Body Fat Percentage | Percentage of body fat | BodyFatRecord | HKQuantityTypeIdentifier.bodyFatPercentage | BodyFatPercentageHealthDataType<BodyFatPercentageRecord, Percentage> |
Avg, Min, Max |
| Lean Body Mass | Mass of body excluding fat | LeanBodyMassRecord | HKQuantityTypeIdentifier.leanBodyMass | LeanBodyMassHealthDataType<LeanBodyMassRecord, Mass> |
Avg, Min, Max |
| Body Temperature | Core body temperature | BodyTemperatureRecord | HKQuantityTypeIdentifier.bodyTemperature | BodyTemperatureHealthDataType<BodyTemperatureRecord, Temperature> |
Avg, Min, Max |
β€οΈ Vitals
| Data Type | Description | Android Health Connect | iOS HealthKit | SDK Data Type | Aggregation |
|---|---|---|---|---|---|
| Heart Rate Series | Heart rate measurements over time | HeartRateRecord | β | HeartRateSeriesRecordHealthDataType<HeartRateSeriesRecord, Frequency> |
Avg, Min, Max |
| Heart Rate Measurement | Single heart rate measurement | β | HKQuantityTypeIdentifier.heartRate | HeartRateMeasurementRecordHealthDataType<HeartRateMeasurementRecord, Frequency> |
Avg, Min, Max |
| Resting Heart Rate | Heart rate while at rest | RestingHeartRateRecord | HKQuantityTypeIdentifier.restingHeartRate | RestingHeartRateHealthDataType<RestingHeartRateRecord, Frequency> |
Avg, Min, Max |
| Blood Pressure | Systolic and diastolic blood pressure | BloodPressureRecord | HKCorrelationTypeIdentifier.bloodPressure | BloodPressureHealthDataType<BloodPressureRecord, Pressure> |
Avg, Min, Max |
| Systolic Blood Pressure | Upper blood pressure value | β | HKQuantityTypeIdentifier.bloodPressureSystolic | SystolicBloodPressureHealthDataType<SystolicBloodPressureRecord, Pressure> |
Avg, Min, Max |
| Diastolic Blood Pressure | Lower blood pressure value | β | HKQuantityTypeIdentifier.bloodPressureDiastolic | DiastolicBloodPressureHealthDataType<DiastolicBloodPressureRecord, Pressure> |
Avg, Min, Max |
| Oxygen Saturation | Blood oxygen saturation percentage | OxygenSaturationRecord | HKQuantityTypeIdentifier.oxygenSaturation | OxygenSaturationHealthDataType<OxygenSaturationRecord, Percentage> |
Avg, Min, Max |
| Respiratory Rate | Breathing rate (breaths per minute) | RespiratoryRateRecord | HKQuantityTypeIdentifier.respiratoryRate | RespiratoryRateHealthDataType<RespiratoryRateRecord, Frequency> |
Avg, Min, Max |
| VOβ Max | Maximum oxygen consumption | Vo2MaxRecord | HKQuantityTypeIdentifier.vo2Max | Vo2MaxHealthDataType<Vo2MaxRecord, Vo2Max> |
Avg, Min, Max |
| Blood Glucose | Blood glucose concentration | BloodGlucoseRecord | HKQuantityTypeIdentifier.bloodGlucose | BloodGlucoseHealthDataType<BloodGlucoseRecord, BloodGlucose> |
Avg, Min, Max |
π΄ Sleep
| Data Type | Description | Android Health Connect | iOS HealthKit | SDK Data Type | Aggregation |
|---|---|---|---|---|---|
| Sleep Session | Complete sleep session with sleep stages | SleepSessionRecord | β | SleepSessionHealthDataType<SleepSessionRecord, Duration> |
- |
| Sleep Stage Record | Individual sleep stage measurement | β | HKCategoryTypeIdentifier.sleepAnalysis | SleepStageRecordHealthDataType<SleepStageRecord, Duration> |
- |
ποΈ Exercise & Workouts
| Data Type | Description | Android Health Connect | iOS HealthKit | SDK Data Type | Aggregation |
|---|---|---|---|---|---|
| Exercise Session | Complete workout session with exercise type and stats | ExerciseSessionRecord | HKWorkout | ExerciseSessionHealthDataType<ExerciseSessionRecord, Duration> |
Duration |
Supported Exercise Types
The SDK supports 100+ exercise types across both platforms, including:
Cross-Platform Types (~50 types supported on both iOS and Android):
- Cardio: running, walking, cycling, hiking, swimming
- Strength: strength training, calisthenics, weightlifting
- Team Sports: basketball, soccer, tennis, volleyball, baseball, rugby
- Racquet Sports: tennis, badminton, squash, table tennis
- Winter Sports: snowboarding, skating
- Fitness: yoga, pilates, HIIT, elliptical
- Water Sports: surfing, water polo, rowing, sailing, paddling, diving
- And many more: golf, climbing, boxing, martial arts, gymnastics, fencing
iOS-Only Types (annotated with @supportedOnAppleHealth):
swimming(generic),waterFitness,waterSportskickboxing,wrestling,taiChihandCycling,trackAndFieldcrossCountrySkiing,downhillSkiing,snowSports,curlingpickleball,lacrosse,hockey,discSportsarchery,bowling,fishing,hunting,equestrianSportsbarre,cardioDance,socialDance,coreTrainingcrossTraining,jumpRope,fitnessGaming,mixedCardiostepTraining,mindAndBody,preparationAndRecovery,cooldownwheelchairWalkPace,wheelchairRunPacetransition,swimBikeRun,play
Android-Only Types (annotated with @supportedOnHealthConnect):
runningTreadmill,cyclingStationaryswimmingOpenWater,swimmingPoolweightlifting,calisthenicsiceHockey,rollerHockeyskiing,snowshoeingdancing,exerciseClass,bootCampguidedBreathing,paragliding,wheelchair
Important
Attempting to use a platform-specific exercise type on an unsupported platform will result in UnsupportedOperationException.
Platform Mapping Details:
- Android Health Connect: Maps to
ExerciseSessionRecord.EXERCISE_TYPE_*constants - iOS HealthKit: Maps to
HKWorkoutActivityTypeenum values
For complete exercise type documentation and platform mappings, see the ExerciseType enum documentation.
π Nutrition
Core & Hydration
| Data Type | Description | Android Health Connect | iOS HealthKit | SDK Data Type | Aggregation |
|---|---|---|---|---|---|
| Nutrition (composite) | Complete nutrition record with macros and micronutrients | NutritionRecord | HKCorrelationType.food | NutritionHealthDataType<NutritionRecord, Energy> |
- |
| Energy | Total energy intake from food | NutritionRecord (NutritionRecord.energy field) | HKQuantityTypeIdentifier.dietaryEnergyConsumed | EnergyNutrientHealthDataType<EnergyNutrientRecord, Energy> (iOS HealthKit Only) |
Sum |
| Hydration/Water | Water and fluid intake | HydrationRecord | HKQuantityTypeIdentifier.dietaryWater | HydrationHealthDataType<HydrationRecord, Volume> |
Sum |
Macronutrients
| Data Type | Description | Android Health Connect | iOS HealthKit | SDK Data Type | Aggregation |
|---|---|---|---|---|---|
| Protein | Protein intake | NutritionRecord (NutritionRecord.protein) | HKQuantityTypeIdentifier.dietaryProtein | ProteinNutrientDataType<ProteinNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Total Carbohydrate | Total carbs intake | NutritionRecord (NutritionRecord.carbs) | HKQuantityType Identifier.dietaryCarbohydrates | TotalCarbohydrateNutrientDataType<TotalCarbohydrateNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Total Fat | Total fat intake | NutritionRecord (NutritionRecord.totalFat) | HKQuantityTypeIdentifier.dietaryFatTotal | TotalFatNutrientDataType<TotalFatNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Caffeine | Caffeine intake | NutritionRecord (NutritionRecord.caffeine) | HKQuantityTypeIdentifier.dietaryCaffeine | CaffeineNutrientDataType<CaffeineNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
Fats
| Data Type | Description | Android Health Connect | iOS HealthKit | SDK Data Type | Aggregation |
|---|---|---|---|---|---|
| Saturated Fat | Saturated fat intake | NutritionRecord (NutritionRecord.saturatedFat) | HKQuantityTypeIdentifier.dietaryFatSaturated | SaturatedFatNutrientDataType<SaturatedFatNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Monounsaturated Fat | Monounsaturated fat intake | NutritionRecord (NutritionRecord.monounsaturatedFat) | HKQuantityTypeIdentifier.dietaryFatMonounsaturated | MonounsaturatedFatNutrientDataType<MonounsaturatedFatNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Polyunsaturated Fat | Polyunsaturated fat intake | NutritionRecord (NutritionRecord.polyunsaturatedFat) | HKQuantityTypeIdentifier.dietaryFatPolyunsaturated | PolyunsaturatedFatNutrientDataType<PolyunsaturatedFatNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Cholesterol | Cholesterol intake | NutritionRecord (NutritionRecord.cholesterol) | HKQuantityTypeIdentifier.dietaryCholesterol | CholesterolNutrientDataType<CholesterolNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
Fiber & Sugar
| Data Type | Description | Android Health Connect | iOS HealthKit | SDK Data Type | Aggregation |
|---|---|---|---|---|---|
| Dietary Fiber | Dietary fiber intake | NutritionRecord (NutritionRecord.dietaryFiber) | HKQuantityTypeIdentifier.dietaryFiber | DietaryFiberNutrientDataType<DietaryFiberNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Sugar | Sugar intake | NutritionRecord (NutritionRecord.sugar) | HKQuantityTypeIdentifier.dietarySugar | SugarNutrientDataType<SugarNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
Minerals
| Data Type | Description | Android Health Connect | iOS HealthKit | SDK Data Type | Aggregation |
|---|---|---|---|---|---|
| Calcium | Calcium intake | NutritionRecord (NutritionRecord.calcium) | HKQuantityTypeIdentifier.dietaryCalcium | CalciumNutrientDataType<CalciumNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Iron | Iron intake | NutritionRecord (NutritionRecord.iron) | HKQuantityTypeIdentifier.dietaryIron | IronNutrientDataType<IronNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Magnesium | Magnesium intake | NutritionRecord (NutritionRecord.magnesium) | HKQuantityTypeIdentifier.dietaryMagnesium | MagnesiumNutrientDataType<MagnesiumNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Manganese | Manganese intake | NutritionRecord (NutritionRecord.manganese) | HKQuantityTypeIdentifier.dietaryManganese | ManganeseNutrientDataType<ManganeseNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Phosphorus | Phosphorus intake | NutritionRecord (NutritionRecord.phosphorus) | HKQuantityTypeIdentifier.dietaryPhosphorus | PhosphorusNutrientDataType<PhosphorusNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Potassium | Potassium intake | NutritionRecord (NutritionRecord.potassium) | HKQuantityTypeIdentifier.dietaryPotassium | PotassiumNutrientDataType<PotassiumNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Selenium | Selenium intake | NutritionRecord (NutritionRecord.selenium) | HKQuantityTypeIdentifier.dietarySelenium | SeleniumNutrientDataType<SeleniumNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Sodium | Sodium intake | NutritionRecord (NutritionRecord.sodium) | HKQuantityTypeIdentifier.dietarySodium | SodiumNutrientDataType<SodiumNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Zinc | Zinc intake | NutritionRecord (NutritionRecord.zinc) | HKQuantityTypeIdentifier.dietaryZinc | ZincNutrientDataType<ZincNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
B Vitamins
| Data Type | Description | Android Health Connect | iOS HealthKit | SDK Data Type | Aggregation |
|---|---|---|---|---|---|
| Thiamin (B1) | Thiamin (vitamin B1) intake | NutritionRecord (NutritionRecord.thiamin) | HKQuantityTypeIdentifier.dietaryThiamin | ThiaminNutrientDataType<ThiaminNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Riboflavin (B2) | Riboflavin (vitamin B2) | NutritionRecord (NutritionRecord.riboflavin) | HKQuantityTypeIdentifier.dietaryRiboflavin | RiboflavinNutrientDataType<RiboflavinNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Niacin (B3) | Niacin (vitamin B3) intake | NutritionRecord (NutritionRecord.niacin) | HKQuantityTypeIdentifier.dietaryNiacin | NiacinNutrientDataType<NiacinNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Pantothenic Acid (B5) | Pantothenic acid (vitamin B5) | NutritionRecord (NutritionRecord.pantothenicAcid) | HKQuantityTypeIdentifier.dietaryPantothenicAcid | PantothenicAcidNutrientDataType<PantothenicAcidNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Vitamin B6 | Vitamin B6 intake | NutritionRecord (NutritionRecord.vitaminB6) | HKQuantityTypeIdentifier.dietaryVitaminB6 | VitaminB6NutrientDataType<VitaminB6NutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Biotin (B7) | Biotin (vitamin B7) intake | NutritionRecord (NutritionRecord.biotin) | HKQuantityTypeIdentifier.dietaryBiotin | BiotinNutrientDataType<BiotinNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Folate (B9) | Folate (vitamin B9) intake | NutritionRecord (NutritionRecord.folate) | HKQuantityTypeIdentifier.dietaryFolate | FolateNutrientDataType<FolateNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Vitamin B12 | Vitamin B12 intake | NutritionRecord (NutritionRecord.vitaminB12) | HKQuantityTypeIdentifier.dietaryVitaminB12 | VitaminB12NutrientDataType<VitaminB12NutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
Other Vitamins
| Data Type | Description | Android Health Connect | iOS HealthKit | SDK Data Type | Aggregation |
|---|---|---|---|---|---|
| Vitamin A | Vitamin A intake | NutritionRecord (NutritionRecord.vitaminA) | HKQuantityTypeIdentifier.dietaryVitaminA | VitaminANutrientDataType<VitaminANutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Vitamin C | Vitamin C intake | NutritionRecord (NutritionRecord.vitaminC) | HKQuantityTypeIdentifier.dietaryVitaminC | VitaminCNutrientDataType<VitaminCNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Vitamin D | Vitamin D intake | NutritionRecord (NutritionRecord.vitaminD) | HKQuantityTypeIdentifier.dietaryVitaminD | VitaminDNutrientDataType<VitaminDNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Vitamin E | Vitamin E intake | NutritionRecord (NutritionRecord.vitaminE) | HKQuantityTypeIdentifier.dietaryVitaminE | VitaminENutrientDataType<VitaminENutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
| Vitamin K | Vitamin K intake | NutritionRecord (NutritionRecord.vitaminK) | HKQuantityTypeIdentifier.dietaryVitaminK | VitaminKNutrientDataType<VitaminKNutrientRecord, Mass> (iOS HealthKit Only) |
Sum |
π Speed
| Data Type | Description | Android Health Connect | iOS HealthKit | SDK Data Type | Aggregation |
|---|---|---|---|---|---|
| Speed Series | Speed measurements over time | SpeedRecord | β | SpeedSeriesDataType<SpeedSeriesRecord, Velocity> |
- |
| Walking Speed | Walking speed measurement | β | HKQuantityTypeIdentifier.walkingSpeed | WalkingSpeedDataType<WalkingSpeedRecord, Velocity> |
- |
| Running Speed | Running speed measurement | β | HKQuantityTypeIdentifier.runningSpeed | RunningSpeedDataType<RunningSpeedRecord, Velocity> |
- |
| Stair Ascent Speed | Speed while climbing stairs | β | HKQuantityTypeIdentifier.stairAscentSpeed | StairAscentSpeedDataType<StairAscentSpeedRecord, Velocity> |
- |
| Stair Descent Speed | Speed while descending stairs | β | HKQuantityTypeIdentifier.stairDescentSpeed | StairDescentSpeed DataType<StairDescentSpeedRecord, Velocity> |
- |
π Migration Guides
π€ Contributing
Contributions are welcome! See our GitHub Issues to report bugs or request features.
Development Setup
# Clone the repository
git clone https://github.com/fam-tung-lam/health_connector.git
cd health_connector
# Bootstrap the monorepo
melos bootstrap
# Install dependencies
melos get
# Run analysis
melos analyze:dart
Code Style
This project uses health_connector_lint for consistent code style. Run dart analyze before submitting PRs.
π License
This project is licensed under the Apache 2.0 License - see the LICENSE file for details.
π Changelog
See CHANGELOG.md for version history.
Libraries
- health_connector
- Cross-platform health and fitness data integration for Flutter.
- health_connector_internal
- Cross-platform health and fitness data integration for Flutter.









