health_connector 3.5.1
health_connector: ^3.5.1 copied to clipboard
The most comprehensive Flutter health plugin for seamless iOS HealthKit and Android Health Connect integration.
health_connector #
Production-grade Flutter SDK for iOS HealthKit and Android Health Connect. Access 100+ health data types with compile-time type safety, incremental data synchronization, and privacy-first architecture.
๐ Table of Contents #
๐ฎ See It In Action โ Interactive Toolbox Demo #
See what's possible. The Health Connector Toolbox showcases the full power of the SDK with live, interactive demonstrations running on both iOS and Android.
| ๐ Permissions | ๐ Read | โ๏ธ Write | ๐๏ธ Delete | ๐ Aggregate |
|---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
๐ Try It Yourself #
git clone https://github.com/fam-tung-lam/health_connector.git
cd health_connector/examples/health_connector_toolbox
flutter pub get && flutter run
Note: The toolbox app is used only for demonstration purposes and as an internal tool for manually testing SDK features. It is not intended for production reference.
๐ Quick Start #
๐ Requirements #
| Component | Requirements |
|---|---|
| Flutter | โข SDK: โฅ3.35.7 |
| Android | โข OS: API 26+ โข Languages: Kotlin 2.1.0, Java 17 |
| iOS | โข OS: โฅ15.0 โข Language: Swift 5.9 |
โจ Upgrading is Easy:
- Flutter 3.35.7 has great backward compatibility up to Flutter 3.32.0, making the
migration very straightforward and requiring no changes to your existing code. For projects
> already using Material 3 UI, great backward compatibility extends up to **Flutter 3.27.0**.
- Swift 5.9 has great backward compatibility up to Swift 5.0, and Kotlin 2.1 up to
Kotlin 2.0. Migration is very straightforward โ simply update version in your build
configuration
> files. **No changes to your existing native code are required.**
๐ฆ Installation #
flutter pub add health_connector
Or add manually to pubspec.yaml:
dependencies:
health_connector: [ latest_version ]
๐ง Platform Setup #
๐ค Android Health Connect Setup
Step 1: Update AndroidManifest.xml
Update 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" />
<!-- Add more read permissions... -->
<!-- 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" />
<!-- Add more write permissions... -->
<!-- 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" />
<!-- Add more feature permissions... -->
</manifest>
โ Important: You must declare a permission for each health data type and feature your app accesses. See
the Health Connect data types list
for all available permissions.
Step 2: Update MainActivity (Android 14+)
This SDK uses the modern registerForActivityResult API when requesting permissions from Health
Connect. For this to work correctly, your app's MainActivity must extend FlutterFragmentActivity
instead of FlutterActivity.
Update android/app/src/main/kotlin/.../MainActivity.kt:
package com.example.yourapp
import io.flutter.embedding.android.FlutterFragmentActivity
class MainActivity : FlutterFragmentActivity() {
// Your existing code
}
Step 3: Enable AndroidX
Health Connect is built on AndroidX libraries. android.useAndroidX=true enables AndroidX support,
and android.enableJetifier=true automatically migrates third-party libraries to use AndroidX.
Update android/gradle.properties:
# Your existing configuration
android.enableJetifier=true
android.useAndroidX=true
Step 4: Set Minimum Android Version
Health Connect requires Android 8.0 (API 26) or higher.
Update android/app/build.gradle:
android {
// Your existing configuration
defaultConfig {
// Your existing configuration
minSdkVersion 26 // Required for Health Connect
}
}
๐ iOS HealthKit Setup
Step 1: Configure Xcode
- Open your project in Xcode (
ios/Runner.xcworkspace) - Select your app target
- In General tab โ Set Minimum Deployments to 15.0
- In Signing & Capabilities tab โ Click + Capability โ Add HealthKit
Step 2: 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 Demo #
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(
const HealthConnectorConfig(
loggerConfig: HealthConnectorLoggerConfig(
logProcessors: [PrintLogProcessor()],
),
),
);
// 3. Request permissions
final results = await connector.requestPermissions([
HealthDataType.steps.readPermission,
HealthDataType.steps.writePermission,
]);
// 4. Verify permissions were granted
final granted = results.every((r) => r.status != PermissionStatus.denied);
if (!granted) {
print('Permissions denied');
return;
}
// 5. Write health data
final now = DateTime.now();
final records = [
StepsRecord(
id: HealthRecordId.none,
startTime: now.subtract(Duration(hours: 3)),
endTime: now.subtract(Duration(hours: 2)),
count: Number(1500),
metadata: Metadata.automaticallyRecorded(
device: Device.fromType(DeviceType.phone),
),
),
StepsRecord(
id: HealthRecordId.none,
startTime: now.subtract(Duration(hours: 2)),
endTime: now.subtract(Duration(hours: 1)),
count: Number(2000),
metadata: Metadata.automaticallyRecorded(
device: Device.fromType(DeviceType.phone),
),
),
];
final recordIds = await connector.writeRecords(records);
print('Wrote ${recordIds.length} records');
// 6. Read health data
final response = await connector.readRecords(
HealthDataType.steps.readInTimeRange(
startTime: now.subtract(Duration(days: 1)),
endTime: now,
),
);
print('Found ${response.records.length} records:');
for (final record in response.records) {
print(
' โ ${record.count.value} steps (${record.startTime}-${record.endTime})',
);
}
// 7. Aggregate health data
final totalSteps = await connector.aggregate(
HealthDataType.steps.aggregateSum(
startTime: now.subtract(Duration(days: 1)),
endTime: now,
),
);
print('Total steps: ${totalSteps.value.value}');
// 8. Delete health data
await connector.deleteRecords(HealthDataType.steps.deleteByIds(recordIds));
print('Deleted ${recordIds.length} records');
}
What's Next?
- Check out the Developer Guide for full API documentation, error handling,
and advanced features.
- Check out the Supported Health Data Types.
๐ Developer Guide #
๐ Manage Permissions #
Check Permission Status
iOS Privacy: HealthKit purposefully restricts access to read authorization status to protect user privacy. The SDK explicitly exposes this platform behavior by returning
unknownfor all iOS read permissions. This is a native privacy feature, not an SDK limitation.
final status = await connector.getPermissionStatus(
HealthDataType.steps.readPermission,
);
switch (status) {
case PermissionStatus.granted:
print('Steps read permission granted');
case PermissionStatus.denied:
print('Steps read permission denied');
case PermissionStatus.unknown:
print('Steps read permission unknown (iOS read)');
}
Workaround: Detecting iOS Read Status
Disclaimer: This workaround attempts to infer permission status, which bypasses HealthKit's intended privacy design. Use only if your app genuinely needs to determine read permission status.
Since iOS returns unknown for read permissions, you can infer the status by attempting a minimal
read operation. If the read fails with AuthorizationException, permission is definitively denied.
Future<bool> hasReadPermission(HealthDataType dataType) async {
try {
// Attempt to read a single record to check access
await connector.readRecords(
dataType.readInTimeRange(
startTime: DateTime.now().subtract(Duration(days: 1)),
endTime: DateTime.now(),
pageSize: 1, // Minimize data transfer
),
);
return true; // Read succeeded (or returned empty) -> Permission granted
} on AuthorizationException {
return false; // Explicitly denied
}
}
Request Permissions
// 1. Define permissions to request
final permissions = [
HealthDataType.steps.readPermission,
HealthDataType.steps.writePermission,
HealthDataType.weight.readPermission,
HealthPlatformFeature.readHealthDataInBackground.permission,
];
// 2. Request permissions
final results = await connector.requestPermissions(permissions);
// 3. Process results
for (final result in results) {
switch (result.status) {
case PermissionStatus.granted:
print('Granted: ${result.permission}');
case PermissionStatus.denied:
print('Denied: ${result.permission}');
case PermissionStatus.unknown:
print('Unknown: ${result.permission} (iOS read permission)');
}
}
Get All Granted Permissions (Android Health Connect only)
iOS Privacy: HealthKit does not allow apps to enumerate granted permissions, preventing user fingerprinting. This API throws
UnsupportedOperationExceptionon iOS.
try {
final grantedPermissions = await connector.getGrantedPermissions();
for (final permission in grantedPermissions) {
print(
'Granted: ${permission.dataType} (${permission.accessType})',
); // Example: โ
Granted: HealthDataType.steps (read)
}
} on UnsupportedOperationException {
print('Listing granted permissions is not supported on iOS');
}
Revoke All Permissions (Android Health Connect only)
iOS Privacy: HealthKit does not support programmatic permission revocation. Users must manage permissions in the iOS Settings app. This API throws
UnsupportedOperationExceptionon iOS.
try {
await connector.revokeAllPermissions();
print('Permissions revoked');
} on UnsupportedOperationException {
print('Programmatic revocation is not supported on iOS');
}
๐ Read Data #
Historical Data Access:
- Android Health Connect defaults to 30 daysโrequest
HealthPlatformFeature.readHealthDataHistorypermission for older data.- iOS HealthKit has no restrictions for historical data access.
Read by ID
// 1. Define read request
final readRequest = HealthDataType.steps.readById(
HealthRecordId('record-id'),
);
// 2. Process read request
final record = await connector.readRecord(readRequest);
// 3. Process result
if (record != null) {
print('Found: ${record.count.value} steps');
} else {
print('No record found.');
}
Read by Time Range
// 1. Define read request
final readRequest = HealthDataType.steps.readInTimeRange(
startTime: DateTime.now().subtract(Duration(days: 7)),
endTime: DateTime.now(),
);
// 2. Process read request
final response = await connector.readRecords(readRequest);
// 3. Process result
print('Found ${response.records.length} records');
for (final record in response.records) {
print('${record.count.value} steps on ${record.startTime}');
}
Sort Records by Time
// Sort oldest first (ascending)
final oldestFirst = await connector.readRecords(
HealthDataType.steps.readInTimeRange(
startTime: DateTime.now().subtract(Duration(days: 7)),
endTime: DateTime.now(),
sortDescriptor: SortDescriptor.timeAscending,
),
);
// Sort newest first (descending) - default behavior
final newestFirst = await connector.readRecords(
HealthDataType.steps.readInTimeRange(
startTime: DateTime.now().subtract(Duration(days: 7)),
endTime: DateTime.now(),
sortDescriptor: SortDescriptor.timeDescending, // Default
),
);
Paginate Through All Records
// 1. Create read request with configured page size
var request = HealthDataType.steps.readInTimeRange(
startTime: DateTime.now().subtract(Duration(days: 30)),
endTime: DateTime.now(),
pageSize: 100,
);
// 2. Fetch all pages
final allRecords = <StepsRecord>[];
while (true) {
final response = await connector.readRecords(request);
allRecords.addAll(response.records.cast<StepsRecord>());
// Check if there are more pages
if (response.nextPageRequest == null) {
print('No more pages');
break;
}
print('Fetching next page...');
request = response.nextPageRequest!;
}
// 3. Print total records
print('Total: ${allRecords.length} records');
๐พ Write Data #
Write Single Record
// 1. Create record
final record = StepsRecord(
// `id` must be `HealthRecordId.none` for new records
id: HealthRecordId.none,
startTime: DateTime.now().subtract(Duration(hours: 1)),
endTime: DateTime.now(),
count: Number(5000),
metadata: Metadata.automaticallyRecorded(
device: Device.fromType(DeviceType.phone),
),
);
// 2. Write record
final recordId = await connector.writeRecord(record);
print('Saved: $recordId');
Batch Write Multiple Records
final now = DateTime.now();
// 1. Create records
final records = [
StepsRecord(
id: HealthRecordId.none,
startTime: now.subtract(Duration(hours: 3)),
endTime: now.subtract(Duration(hours: 2)),
count: Number(1500),
metadata: Metadata.automaticallyRecorded(
device: Device.fromType(DeviceType.phone),
),
),
WeightRecord(
id: HealthRecordId.none,
time: now.subtract(Duration(hours: 1)),
weight: Mass.fromKilograms(70.5),
metadata: Metadata.automaticallyRecorded(
device: Device.fromType(DeviceType.phone),
),
),
HeightRecord(
id: HealthRecordId.none,
time: now,
height: Length.fromMeters(1.75),
metadata: Metadata.automaticallyRecorded(
device: Device.fromType(DeviceType.phone),
),
),
];
// 2. Write records (atomic operationโall succeed or all fail)
final ids = await connector.writeRecords(records);
print('Wrote ${ids.length} records');
๐๏ธ Delete Data #
Note: Apps can only delete records they createdโthis is a platform security restriction. Attempting to delete records created by other apps will throw an
AuthorizationException.
Delete by IDs
// 1. Define delete request
final request = HealthDataType.steps.deleteByIds([
HealthRecordId('id-1'),
HealthRecordId('id-2'),
]);
// 2. Delete specific steps records by IDs (atomic operationโall succeed or all fail)
await connector.deleteRecords(request);
print('Deleted');
Delete by Time Range
// 1. Define delete request
final request = HealthDataType.steps.deleteInTimeRange(
startTime: DateTime.now().subtract(Duration(days: 7)),
endTime: DateTime.now(),
);
// 2. Delete all steps records created in the past week (atomic operationโall succeed or all fail)
await connector.deleteRecords(request);
๐ Update Data #
iOS Limitation: HealthKit uses an immutable data modelโrecords cannot be updated, only deleted and recreated. This is a platform security restriction.
Update Single Record (Android Health Connect only)
// 1. Fetch record to update
final record = await connector.readRecord(
HealthDataType.steps.readById(HealthRecordId('record-id')),
);
// 2. Update record value
await connector.updateRecord(
record.copyWith(count: Number(record.count.value + 500)),
);
print('Record updated');
iOS Workaround: Delete + Recreate
// 1. Delete existing record
await connector.deleteRecords(
HealthDataType.steps.deleteByIds([existingRecord.id]),
);
// 2. Change record value
final newRecord = existingRecord.copyWith(
id: HealthRecordId.none,
count: Number(newValue),
);
// 3. Write new record with updated value
final newId = await connector.writeRecord(
newRecord,
); // โ ๏ธ Note: ID changes after recreation
Batch Update (Android Health Connect only)
// 1. Fetch records to update
final response = await connector.readRecords(
HealthDataType.steps.readInTimeRange(
startTime: DateTime.now().subtract(Duration(days: 7)),
endTime: DateTime.now(),
),
);
// 2. Apply changes
final updated = response.records
.map((r) => r.copyWith(count: Number(r.count.value + 100)))
.toList();
// 3. Update records (atomic operationโall succeed or all fail)
await connector.updateRecords(updated);
print('Updated ${updated.length} records');
โ Aggregate Data #
final now = DateTime.now();
final thirtyDaysAgo = now.subtract(Duration(days: 30));
// Calculate total steps for the past 30 days
final sumResult = await connector.aggregate(
HealthDataType.steps.aggregateSum(
startTime: thirtyDaysAgo,
endTime: now,
),
);
print('Total steps: ${sumResult.value}');
// Calculate average weight for the past 30 days
final avgResult = await connector.aggregate(
HealthDataType.weight.aggregateAvg(
startTime: thirtyDaysAgo,
endTime: now,
),
);
print('Average weight: ${avgResult.inKilograms} kg');
// Calculate minimum weight for the past 30 days
final minResult = await connector.aggregate(
HealthDataType.weight.aggregateMin(
startTime: thirtyDaysAgo,
endTime: now,
),
);
print('Minimum weight: ${minResult.inKilograms} kg');
// Calculate maximum weight for the past 30 days
final maxResult = await connector.aggregate(
HealthDataType.weight.aggregateMax(
startTime: thirtyDaysAgo,
endTime: now,
),
);
print('Maximum weight: ${maxResult.inKilograms} kg');
๐ Synchronize Data #
Data synchronization is an incremental sync API that retrieves only health data that has changed since your last sync, dramatically reducing bandwidth usage and improving performance for apps that need to stay up-to-date with health data.
When to Use Sync vs Regular Reads
| Use Case | Recommended Approach |
|---|---|
| Periodic background sync (e.g., daily health data updates) | โ
Use synchronize() |
| Real-time monitoring of ongoing activity | โ
Use synchronize() |
| One-time data fetch for a specific time range | Use readRecords() |
| User-requested historical data (e.g., "show me last month") | Use readRecords() |
How Synchronization Works
Synchronization follows a two-phase flow:
-
Phase 1: Set Checkpoint (one-time setup)
- Call
synchronize()withsyncToken: null - This establishes a point-in-time marker (no data is returned)
- Save the returned
nextSyncTokenfor later use
- Call
-
Phase 2: Fetch Changes (repeated syncs)
- Call
synchronize()with your savedsyncToken - Receive only records that changed since that token was created
- Upserted records: New or updated records since last sync
- Deleted record IDs: Records that were deleted since last sync
- Always save the new
nextSyncTokento continue tracking changes
- Call
Example: Complete Sync Flow
import 'package:health_connector/health_connector.dart';
// Use SharedPreferences, secure storage, or your preferred persistence layer
final storage = LocalTokenStorage();
// Step 1: Set Initial Checkpoint
Future<void> setupSyncCheckpoint() async {
final connector = await HealthConnector.create();
// Pass null to establish "now" as the starting synchronization point
final result = await connector.synchronize(
dataTypes: [HealthDataType.steps, HealthDataType.heartRate],
syncToken: null,
);
// Save token for future syncs
await storage.saveToken(result.nextSyncToken.toJson());
print('Sync checkpoint established');
}
// Step 2: Fetch Changes Since Last Sync
Future<void> syncHealthData() async {
final connector = await HealthConnector.create();
// Load saved token
final tokenJson = await storage.loadToken();
if (tokenJson == null) {
print('No checkpoint found. Run setupSyncCheckpoint() first.');
return;
}
final token = HealthDataSyncToken.fromJson(tokenJson);
// Fetch changes since the token was created
final result = await connector.synchronize(
dataTypes: [HealthDataType.steps, HealthDataType.heartRate],
syncToken: token, // Use saved token
);
print('Sync results:');
print(' โข New/updated records: ${result.upsertedRecords.length}');
print(' โข Deleted record IDs: ${result.deletedRecordIds.length}');
// Process upserted records (new or modified)
for (final record in result.upsertedRecords) {
print('Upserted record: $record');
}
// Process deletions
for (final id in result.deletedRecordIds) {
print('Deleted record ID: $id');
}
// IMPORTANT: Always save the new token for the next sync
await storage.saveToken(result.nextSyncToken.toJson());
print('Sync complete');
}
Handling Pagination
When there are many changes, results are paginated automatically. Use hasMore to detect
pagination and fetch all pages in a loop:
Future<void> syncAllPages() async {
final connector = await HealthConnector.create();
// Load sync token from storage
final tokenJson = await storage.loadToken();
if (tokenJson == null) {
print('No checkpoint found');
return;
}
var token = HealthDataSyncToken.fromJson(tokenJson);
final allUpsertedRecords = <HealthRecord>[];
final allDeletedRecordIds = <HealthRecordId>[];
// Fetch all pages until hasMore is false
do {
final result = await connector.synchronize(
dataTypes: [HealthDataType.steps],
syncToken: token,
);
allUpsertedRecords.addAll(result.upsertedRecords);
allDeletedRecordIds.addAll(result.deletedRecordIds);
// Update token for next page
token = result.nextSyncToken;
print('Fetched page with:');
print(' โข New/updated records: ${result.upsertedRecords.length}');
print(' โข Deleted record IDs: ${result.deletedRecordIds.length}');
} while (result.hasMore);
// Process all changes together
print('Sync results:');
print(' โข New/updated records: ${allUpsertedRecords.length}');
print(' โข Deleted record IDs: ${allDeletedRecordIds.length}');
// Save the final token for the next synchronization
await storage.saveToken(token.toJson());
}
โ๏ธ Manage Features #
Check Feature Availability
final status = await connector.getFeatureStatus(
HealthPlatformFeature.readHealthDataInBackground,
);
if (status == HealthPlatformFeatureStatus.available) {
await connector.requestPermissions([
HealthPlatformFeature.readHealthDataInBackground.permission,
]);
print('Feature available and requested');
} else {
print('Feature not availableโimplement fallback');
}
Note: All features are built directly into the OS and are always available. On Android, Health Connect features may vary depending on the installed app and Android version. Use
getFeatureStatus()to verify feature support on the user's device before requesting permissions.
โ ๏ธ Error Handling #
Every HealthConnectorException thrown by the SDK includes a HealthConnectorErrorCode that
provides specific details about what went wrong. Use this code to handle errors programmatically.
| Error Code | Exception Type | Platform | Description & Causes | Recovery Strategy |
|---|---|---|---|---|
permissionNotGranted |
AuthorizationException |
Both | Permission denied, revoked, or not determined. | Request permissions or guide user to settings. |
permissionNotDeclared |
ConfigurationException |
All | Missing required permission in AndroidManifest.xml or Info.plist. |
Developer Error: Add missing permissions to your app configuration. |
healthServiceUnavailable |
HealthServiceUnavailableException |
All | Device doesn't support Health Connect (Android) or HealthKit (iPad). | Check getHealthPlatformStatus(). Gracefully disable health features. |
healthServiceRestricted |
HealthServiceUnavailableException |
All | Health data access restricted by system policy (e.g. parental controls). | Gracefully disable health features and inform the user. |
healthServiceNotInstalledOrUpdateRequired |
HealthServiceUnavailableException |
Android | Health Connect app is missing or needs an update. | Prompt user to install/update via launchHealthAppPageInAppStore(). |
healthServiceDatabaseInaccessible |
HealthServiceException |
iOS | Device is locked and health database is encrypted/inaccessible. | Wait for device unlock or notify user to unlock their device. |
ioError |
HealthServiceException |
Android | Device storage I/O failed while reading/writing records. | Retry operation with exponential backoff. |
remoteError |
HealthServiceException |
Android | IPC communication with the underlying health service failed. | Retry operation; usually a temporary system glitch. |
rateLimitExceeded |
HealthServiceException |
Android | API request quota exhausted. | Wait and retry later. Implement exponential backoff. |
dataSyncInProgress |
HealthServiceException |
Android | Health Connect is currently syncing data; operations locked. | Retry after a short delay. |
invalidArgument |
InvalidArgumentException |
All | Invalid parameter, malformed record, or expired usage of a token. | Validate input. For expired sync tokens, restart sync with syncToken: null. |
unsupportedOperation |
UnsupportedOperationException |
All | The requested operation is not supported on the current platform or OS version (e.g. accessing Android-only data types on iOS). | Check @supportedOn annotations in documentation before using the API. |
unknownError |
UnknownException |
All | An unclassified internal system error occurred. | Log the error details for debugging. |
Example: Error Handling
try {
await connector.writeRecord(record);
} on AuthorizationException catch (e) {
print('Authorization failed: ${e.message}');
} on HealthServiceUnavailableException catch (e) {
print('Health service unavailable: ${e.code}');
} on HealthServiceException catch (e) {
switch (e.code) {
case HealthConnectorErrorCode.rateLimitExceeded:
print('Rate limit exceeded. Retrying in 5s...');
break;
case HealthConnectorErrorCode.dataSyncInProgress:
print('Health Connect is busy syncing... Retrying later...');
break;
case HealthConnectorErrorCode.remoteError:
case HealthConnectorErrorCode.ioError:
print('Temporary system glitches. Retrying later...');
break;
default:
print('Health Service Warning: ${e.message}');
break;
}
} on InvalidArgumentException catch (e) {
print('Invalid data or expired token: ${e.message}');
} catch (e, stack) {
print('Unexpected system error: $e');
}
๐ Logging #
Health data is sensitive, and user privacy is paramount. The Health Connector SDK adopts a strict zero-logging policy by default:
- No Internal Logging: The SDK never writes to
print,stdout, or platform logs ( Logcat/Console) on its own. - Full Control: You decide exactly where logs go. Even low-level logs from native Swift/Kotlin code are routed through to Dart, giving you a single control plane for all SDK activity.
- Compliance Ready: This architecture ensures no sensitive data is accidentally logged, making it easier to comply with privacy regulations (GDPR, HIPAA) and pass security reviews.
The system is configured via HealthConnectorLoggerConfig, where you define a list of
logProcessors. Each processor handles logs independently and asynchronously.
Setup with Built-in Processors
// Configure logging with built-in processors
final connector = await HealthConnector.create(
const HealthConnectorConfig(
loggerConfig: HealthConnectorLoggerConfig(
enableNativeLogging: false, // Optional: forward native Kotlin/Swift logs
logProcessors: [
// Print warnings and errors to console
PrintLogProcessor(
levels: [
HealthConnectorLogLevel.warning,
HealthConnectorLogLevel.error,
],
),
// Send all logs to dart:developer (integrates with DevTools)
DeveloperLogProcessor(
levels: HealthConnectorLogLevel.values,
),
],
),
),
);
Custom Processor Example
Create your own processor for custom logging needs:
// Example: File logging processor
class FileLogProcessor extends HealthConnectorLogProcessor {
final File logFile;
const FileLogProcessor({
required this.logFile,
super.levels = HealthConnectorLogLevel.values,
});
@override
Future<void> process(HealthConnectorLog log) async {
try {
final formatted = '${log.dateTime} [${log.level.name.toUpperCase()}] '
'${log.message}\n';
await logFile.writeAsString(formatted, mode: FileMode.append);
} catch (e) {
// Handle errors gracefully
debugPrint('Failed to write log: $e');
}
}
@override
bool shouldProcess(HealthConnectorLog log) {
// Custom filtering logic
return super.shouldProcess(log) &&
log.level == HealthConnectorLogLevel.error;
}
}
// Use custom processor
final connector = await HealthConnector.create(
HealthConnectorConfig(
loggerConfig: HealthConnectorLoggerConfig(
logProcessors: [
FileLogProcessor(logFile: File('/path/to/app.log')),
],
),
),
);
๐ Supported Health Data Types #
๐ Activity #
General Activity
| Data Type | Description | Data Type | Supported Aggregation | Supported On | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|---|
| Steps | Number of steps taken | HealthDataType.steps |
Sum | Android Health Connect, iOS HealthKit | StepsRecord | HKQuantityTypeIdentifier.stepCount |
| Active Energy Burned | Energy burned through active movement | HealthDataType.activeEnergyBurned |
Sum | Android Health Connect, iOS HealthKit | ActiveEnergyBurnedRecord | HKQuantityTypeIdentifier.activeEnergyBurned |
| Floors Climbed | Number of floors (flights of stairs) climbed | HealthDataType.floorsClimbed |
Sum | Android Health Connect, iOS HealthKit | FloorsClimbedRecord | HKQuantityTypeIdentifier.flightsClimbed |
| Sexual Activity | Sexual activity tracking | HealthDataType.sexualActivity |
- | Android Health Connect, iOS HealthKit | SexualActivityRecord | HKCategoryTypeIdentifier.sexualActivity |
| Wheelchair Pushes | Number of wheelchair pushes | HealthDataType.wheelchairPushes |
Sum | Android Health Connect, iOS HealthKit | WheelchairPushesRecord | HKQuantityTypeIdentifier.pushCount |
| Cycling Cadence | Cycling pedaling cadence | HealthDataType.cyclingPedalingCadence |
Avg, Min, Max | iOS HealthKit (iOS 17+) | CyclingPedalingCadenceRecord | HKQuantityTypeIdentifier.cyclingCadence |
| Total Energy Burned | Total energy burned (active + basal) | HealthDataType.totalEnergyBurned |
Sum | Android Health Connect | TotalEnergyBurnedRecord | - |
| Basal Energy Burned | Energy burned by basal metabolism | HealthDataType.basalEnergyBurned |
Sum | iOS HealthKit | - | HKQuantityTypeIdentifier.basalEnergyBurned |
| Steps Cadence Series | Steps cadence measurements as a series | HealthDataType.stepsCadenceSeries |
Avg, Min, Max | Android Health Connect | StepsCadenceRecord | - |
| Swimming Strokes | Count of strokes taken during swimming | HealthDataType.swimmingStrokes |
Sum | iOS HealthKit | - | HKQuantityTypeIdentifier.swimmingStrokeCount |
| Elevation Gained | Elevation gained | HealthDataType.elevationGained |
Sum | Android Health Connect | ElevationGainedRecord | - |
| Activity Intensity | Moderate to vigorous physical activity | HealthDataType.activityIntensity |
Sum | Android Health Connect | ActivityIntensityRecord | - |
| Apple Exercise Time | Time spent exercising | HealthDataType.exerciseTime |
- | iOS HealthKit | - | HKQuantityTypeIdentifier.appleExerciseTime |
| Apple Move Time | Time spent moving | HealthDataType.moveTime |
- | iOS HealthKit | - | HKQuantityTypeIdentifier.appleMoveTime |
| Apple Stand Time | Time spent standing | HealthDataType.standTime |
- | iOS HealthKit | - | HKQuantityTypeIdentifier.appleStandTime |
Distance Types
| Data Type | Description | Data Type | Supported Aggregation | Supported On | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|---|
| Distance (generic) | Generic distance traveled | HealthDataType.distance |
Sum | Android Health Connect | DistanceRecord | - |
| Walking/Running Distance | Distance covered by walking or running | HealthDataType.walkingRunningDistance |
Sum | iOS HealthKit | - | HKQuantityTypeIdentifier.distanceWalkingRunning |
| Cycling Distance | Distance covered by cycling | HealthDataType.cyclingDistance |
Sum | iOS HealthKit | - | HKQuantityTypeIdentifier.distanceCycling |
| Swimming Distance | Distance covered by swimming | HealthDataType.swimmingDistance |
Sum | iOS HealthKit | - | HKQuantityTypeIdentifier.distanceSwimming |
| Wheelchair Distance | Distance covered using a wheelchair | HealthDataType.wheelchairDistance |
Sum | iOS HealthKit | - | HKQuantityTypeIdentifier.distanceWheelchair |
| Downhill Snow Sports Distance | Distance covered during downhill snow sports | HealthDataType.downhillSnowSportsDistance |
Sum | iOS HealthKit | - | HKQuantityTypeIdentifier.distanceDownhillSnowSports |
| Cross Country Skiing Distance | Distance covered during cross country skiing | HealthDataType.crossCountrySkiingDistance |
Sum | iOS HealthKit | - | HKQuantityTypeIdentifier.distanceCrossCountrySkiing |
| Paddle Sports Distance | Distance covered during paddle sports | HealthDataType.paddleSportsDistance |
Sum | iOS HealthKit (iOS 18+) | - | HKQuantityTypeIdentifier.distancePaddleSports |
| Rowing Distance | Distance covered during rowing | HealthDataType.rowingDistance |
Sum | iOS HealthKit (iOS 18+) | - | HKQuantityTypeIdentifier.distanceRowing |
| Skating Sports Distance | Distance covered during skating sports | HealthDataType.skatingSportsDistance |
Sum | iOS HealthKit (iOS 18+) | - | HKQuantityTypeIdentifier.distanceSkatingSports |
| Six Minute Walk Test Distance | Distance covered during 6-minute walk test | HealthDataType.sixMinuteWalkTestDistance |
Sum | iOS HealthKit | - | HKQuantityTypeIdentifier.sixMinuteWalkTestDistance |
Speed Types
| Data Type | Description | Data Type | Supported Aggregation | Supported On | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|---|
| Speed Series | Speed measurements over time | HealthDataType.speedSeries |
- | Android Health Connect | SpeedRecord | - |
| Walking Speed | Walking speed measurement | HealthDataType.walkingSpeed |
- | iOS HealthKit (iOS 16+) | - | HKQuantityTypeIdentifier.walkingSpeed |
| Running Speed | Running speed measurement | HealthDataType.runningSpeed |
- | iOS HealthKit (iOS 16+) | - | HKQuantityTypeIdentifier.runningSpeed |
| Stair Ascent Speed | Speed while climbing stairs | HealthDataType.stairAscentSpeed |
- | iOS HealthKit (iOS 16+) | - | HKQuantityTypeIdentifier.stairAscentSpeed |
| Stair Descent Speed | Speed while descending stairs | HealthDataType.stairDescentSpeed |
- | iOS HealthKit (iOS 16+) | - | HKQuantityTypeIdentifier.stairDescentSpeed |
Power Types
| Data Type | Description | Data Type | Supported Aggregation | Supported On | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|---|
| Power Series | Power measurements over time | HealthDataType.powerSeries |
Avg, Min, Max | Android Health Connect | PowerRecord | - |
| Cycling Power | Power output during cycling | HealthDataType.cyclingPower |
Avg, Min, Max | iOS HealthKit (iOS 17+) | - | HKQuantityTypeIdentifier.cyclingPower |
| Running Power | Power output during running | HealthDataType.runningPower |
Avg, Min, Max | iOS HealthKit (iOS 16+) | - | HKQuantityTypeIdentifier.runningPower |
Mobility
| Data Type | Description | Data Type | Supported Aggregation | Supported On | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|---|
| Walking Asymmetry Percentage | Percentage of steps with different foot speeds | HealthDataType.walkingAsymmetryPercentage |
Avg, Min, Max | iOS HealthKit | - | HKQuantityTypeIdentifier.walkingAsymmetryPercentage |
| Walking Double Support Percentage | Percentage of steps with both feet on ground | HealthDataType.walkingDoubleSupportPercentage |
Avg, Min, Max | iOS HealthKit | - | HKQuantityTypeIdentifier.walkingDoubleSupportPercentage |
| Walking Step Length | Distance between foot contacts | HealthDataType.walkingStepLength |
Avg, Min, Max | iOS HealthKit | - | HKQuantityTypeIdentifier.walkingStepLength |
| Walking Steadiness | Stability and regularity of gait | HealthDataType.walkingSteadiness |
- | iOS HealthKit | - | HKQuantityTypeIdentifier.appleWalkingSteadiness |
| Walking Steadiness Event | Reduced gait steadiness event | HealthDataType.walkingSteadinessEvent |
- | iOS HealthKit | - | HKCategoryTypeIdentifier.appleWalkingSteadinessEvent |
| Running Ground Contact Time | Time foot is in contact with ground | HealthDataType.runningGroundContactTime |
Avg, Min, Max | iOS HealthKit (iOS 16+) | - | HKQuantityTypeIdentifier.runningGroundContactTime |
| Running Stride Length | Distance covered by a single step | HealthDataType.runningStrideLength |
Avg, Min, Max | iOS HealthKit (iOS 16+) | - | HKQuantityTypeIdentifier.runningStrideLength |
| Number of Times Fallen | Number of times the user has fallen | HealthDataType.numberOfTimesFallen |
Sum | iOS HealthKit | - | HKQuantityTypeIdentifier.numberOfTimesFallen |
Exercise Sessions
| Data Type | Description | Data Type | Supported Aggregation | Supported On | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|---|
| Exercise Session | Complete workout session with exercise type and stats | HealthDataType.exerciseSession |
Duration | Android Health Connect, iOS HealthKit | ExerciseSessionRecord | HKWorkout |
Exercise Types
| Exercise Type | Android Health Connect | iOS HealthKit |
|---|---|---|
ExerciseType.other |
โ | โ |
ExerciseType.running |
โ | โ |
ExerciseType.runningTreadmill |
โ | โ |
ExerciseType.walking |
โ | โ |
ExerciseType.cycling |
โ | โ |
ExerciseType.cyclingStationary |
โ | โ |
ExerciseType.hiking |
โ | โ |
ExerciseType.handCycling |
โ | โ |
ExerciseType.trackAndField |
โ | โ |
ExerciseType.swimming |
โ | โ |
ExerciseType.swimmingOpenWater |
โ | โ |
ExerciseType.swimmingPool |
โ | โ |
ExerciseType.surfing |
โ | โ |
ExerciseType.waterPolo |
โ | โ |
ExerciseType.rowing |
โ | โ |
ExerciseType.sailing |
โ | โ |
ExerciseType.paddling |
โ | โ |
ExerciseType.diving |
โ | โ |
ExerciseType.waterFitness |
โ | โ |
ExerciseType.waterSports |
โ | โ |
ExerciseType.strengthTraining |
โ | โ |
ExerciseType.weightlifting |
โ | โ |
ExerciseType.calisthenics |
โ | โ |
ExerciseType.basketball |
โ | โ |
ExerciseType.soccer |
โ | โ |
ExerciseType.americanFootball |
โ | โ |
ExerciseType.frisbeeDisc |
โ | โ |
ExerciseType.australianFootball |
โ | โ |
ExerciseType.baseball |
โ | โ |
ExerciseType.softball |
โ | โ |
ExerciseType.volleyball |
โ | โ |
ExerciseType.rugby |
โ | โ |
ExerciseType.cricket |
โ | โ |
ExerciseType.handball |
โ | โ |
ExerciseType.iceHockey |
โ | โ |
ExerciseType.rollerHockey |
โ | โ |
ExerciseType.hockey |
โ | โ |
ExerciseType.lacrosse |
โ | โ |
ExerciseType.discSports |
โ | โ |
ExerciseType.tennis |
โ | โ |
ExerciseType.tableTennis |
โ | โ |
ExerciseType.badminton |
โ | โ |
ExerciseType.squash |
โ | โ |
ExerciseType.racquetball |
โ | โ |
ExerciseType.pickleball |
โ | โ |
ExerciseType.skiing |
โ | โ |
ExerciseType.snowboarding |
โ | โ |
ExerciseType.snowshoeing |
โ | โ |
ExerciseType.skating |
โ | โ |
ExerciseType.crossCountrySkiing |
โ | โ |
ExerciseType.curling |
โ | โ |
ExerciseType.downhillSkiing |
โ | โ |
ExerciseType.snowSports |
โ | โ |
ExerciseType.boxing |
โ | โ |
ExerciseType.kickboxing |
โ | โ |
ExerciseType.martialArts |
โ | โ |
ExerciseType.wrestling |
โ | โ |
ExerciseType.fencing |
โ | โ |
ExerciseType.taiChi |
โ | โ |
ExerciseType.dancing |
โ | โ |
ExerciseType.gymnastics |
โ | โ |
ExerciseType.barre |
โ | โ |
ExerciseType.cardioDance |
โ | โ |
ExerciseType.socialDance |
โ | โ |
ExerciseType.yoga |
โ | โ |
ExerciseType.pilates |
โ | โ |
ExerciseType.highIntensityIntervalTraining |
โ | โ |
ExerciseType.elliptical |
โ | โ |
ExerciseType.exerciseClass |
โ | โ |
ExerciseType.bootCamp |
โ | โ |
ExerciseType.guidedBreathing |
โ | โ |
ExerciseType.stairClimbing |
โ | โ |
ExerciseType.crossTraining |
โ | โ |
ExerciseType.jumpRope |
โ | โ |
ExerciseType.fitnessGaming |
โ | โ |
ExerciseType.mixedCardio |
โ | โ |
ExerciseType.cooldown |
โ | โ |
ExerciseType.flexibility |
โ | โ |
ExerciseType.mindAndBody |
โ | โ |
ExerciseType.preparationAndRecovery |
โ | โ |
ExerciseType.stepTraining |
โ | โ |
ExerciseType.coreTraining |
โ | โ |
ExerciseType.golf |
โ | โ |
ExerciseType.archery |
โ | โ |
ExerciseType.bowling |
โ | โ |
ExerciseType.paragliding |
โ | โ |
ExerciseType.climbing |
โ | โ |
ExerciseType.equestrianSports |
โ | โ |
ExerciseType.fishing |
โ | โ |
ExerciseType.hunting |
โ | โ |
ExerciseType.play |
โ | โ |
ExerciseType.wheelchair |
โ | โ |
ExerciseType.wheelchairWalkPace |
โ | โ |
ExerciseType.wheelchairRunPace |
โ | โ |
ExerciseType.transition |
โ | โ |
ExerciseType.swimBikeRun |
โ | โ |
๐ Body Measurements #
| Data Type | Description | Data Type | Supported Aggregation | Supported On | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|---|
| Weight | Body weight measurement | HealthDataType.weight |
Avg, Min, Max | Android Health Connect, iOS HealthKit | WeightRecord | HKQuantityTypeIdentifier.bodyMass |
| Height | Body height measurement | HealthDataType.height |
Avg, Min, Max | Android Health Connect, iOS HealthKit | HeightRecord | HKQuantityTypeIdentifier.height |
| Body Fat Percentage | Percentage of body fat | HealthDataType.bodyFatPercentage |
Avg, Min, Max | Android Health Connect, iOS HealthKit | BodyFatRecord | HKQuantityTypeIdentifier.bodyFatPercentage |
| Lean Body Mass | Mass of body excluding fat | HealthDataType.leanBodyMass |
Avg, Min, Max | Android Health Connect, iOS HealthKit | LeanBodyMassRecord | HKQuantityTypeIdentifier.leanBodyMass |
| Body Temperature | Core body temperature | HealthDataType.bodyTemperature |
Avg, Min, Max | Android Health Connect, iOS HealthKit | BodyTemperatureRecord | HKQuantityTypeIdentifier.bodyTemperature |
| Body Water Mass | Mass of body water | HealthDataType.bodyWaterMass |
Avg, Min, Max | Android Health Connect | BodyWaterMassRecord | - |
| Bone Mass | Mass of bone mineral | HealthDataType.boneMass |
Avg, Min, Max | Android Health Connect | BoneMassRecord | - |
| Body Mass Index | Body Mass Index (BMI) | HealthDataType.bodyMassIndex |
Avg, Min, Max | iOS HealthKit | - | HKQuantityTypeIdentifier.bodyMassIndex |
| Waist Circumference | Waist circumference measurement | HealthDataType.waistCircumference |
Avg, Min, Max | iOS HealthKit | - | HKQuantityTypeIdentifier.waistCircumference |
| Sleeping Wrist Temperature | Temperature measured at the wrist during sleep | HealthDataType.sleepingWristTemperature |
Avg, Min, Max | iOS HealthKit (iOS 16+) | - | HKQuantityTypeIdentifier.appleSleepingWristTemperature |
โค๏ธ Vitals #
| Data Type | Description | Data Type | Supported Aggregation | Supported On | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|---|
| Heart Rate Series | Heart rate measurements over time | HealthDataType.heartRateSeries |
Avg, Min, Max | Android Health Connect | HeartRateRecord | - |
| Heart Rate Measurement | Single heart rate measurement | HealthDataType.heartRate |
Avg, Min, Max | iOS HealthKit | - | HKQuantityTypeIdentifier.heartRate |
| Resting Heart Rate | Heart rate while at rest | HealthDataType.restingHeartRate |
Avg, Min, Max | Android Health Connect, iOS HealthKit | RestingHeartRateRecord | HKQuantityTypeIdentifier.restingHeartRate |
| High Heart Rate Event | High heart rate event detected | HealthDataType.highHeartRateEvent |
- | iOS HealthKit | - | HKCategoryTypeIdentifier.highHeartRateEvent |
| Low Heart Rate Event | Low heart rate event detected | HealthDataType.lowHeartRateEvent |
- | iOS HealthKit | - | HKCategoryTypeIdentifier.lowHeartRateEvent |
| Irregular Heart Rhythm Event | Irregular heart rhythm event detected | HealthDataType.irregularHeartRhythmEvent |
- | iOS HealthKit | - | HKCategoryTypeIdentifier.irregularHeartRhythmEvent |
| Blood Pressure | Systolic and diastolic blood pressure | HealthDataType.bloodPressure |
Avg, Min, Max | Android Health Connect, iOS HealthKit | BloodPressureRecord | HKCorrelationTypeIdentifier.bloodPressure |
| Systolic Blood Pressure | Upper blood pressure value | HealthDataType.systolicBloodPressure |
Avg, Min, Max | iOS HealthKit | - | HKQuantityTypeIdentifier.bloodPressureSystolic |
| Diastolic Blood Pressure | Lower blood pressure value | HealthDataType.diastolicBloodPressure |
Avg, Min, Max | iOS HealthKit | - | HKQuantityTypeIdentifier.bloodPressureDiastolic |
| Oxygen Saturation | Blood oxygen saturation percentage | HealthDataType.oxygenSaturation |
Avg, Min, Max | Android Health Connect, iOS HealthKit | OxygenSaturationRecord | HKQuantityTypeIdentifier.oxygenSaturation |
| Respiratory Rate | Breathing rate (breaths per minute) | HealthDataType.respiratoryRate |
Avg, Min, Max | Android Health Connect, iOS HealthKit | RespiratoryRateRecord | HKQuantityTypeIdentifier.respiratoryRate |
| VOโ Max | Maximum oxygen consumption | HealthDataType.vo2Max |
Avg, Min, Max | Android Health Connect, iOS HealthKit | Vo2MaxRecord | HKQuantityTypeIdentifier.vo2Max |
| Blood Glucose | Blood glucose concentration | HealthDataType.bloodGlucose |
Avg, Min, Max | Android Health Connect, iOS HealthKit | BloodGlucoseRecord | HKQuantityTypeIdentifier.bloodGlucose |
| HRV RMSSD | Heart Rate Variability (RMSSD) | HealthDataType.heartRateVariabilityRMSSD |
- | Android Health Connect | HeartRateVariabilityRMSSDRecord | - |
| HRV SDNN | Heart Rate Variability (SDNN) | HealthDataType.heartRateVariabilitySDNN |
- | iOS HealthKit | - | HKQuantityTypeIdentifier.heartRateVariabilitySDNN |
| Peripheral Perfusion Index | Peripheral blood flow measurement | HealthDataType.peripheralPerfusionIndex |
Avg, Min, Max | iOS HealthKit | - | HKQuantityTypeIdentifier.peripheralPerfusionIndex |
| Forced Vital Capacity | Forced vital capacity measurement | HealthDataType.forcedVitalCapacity |
Avg, Min, Max | iOS HealthKit | - | HKQuantityTypeIdentifier.forcedVitalCapacity |
| Blood Alcohol Content | Blood alcohol content percentage | HealthDataType.bloodAlcoholContent |
Avg, Min, Max | iOS HealthKit | - | HKQuantityTypeIdentifier.bloodAlcoholContent |
| Forced Expiratory Volume | Forced expiratory volume (1s) | HealthDataType.forcedExpiratoryVolume |
Avg, Min, Max | iOS HealthKit | - | HKQuantityTypeIdentifier.forcedExpiratoryVolume1 |
| Atrial Fibrillation Burden | AFib burden percentage | HealthDataType.atrialFibrillationBurden |
Avg, Min, Max | iOS HealthKit (iOS 16+) | - | HKQuantityTypeIdentifier.atrialFibrillationBurden |
| Walking Heart Rate Average | Average heart rate while walking | HealthDataType.walkingHeartRateAverage |
Avg, Min, Max | iOS HealthKit | - | HKQuantityTypeIdentifier.walkingHeartRateAverage |
| Heart Rate Recovery 1 min | Heart rate reduction 1 min after exercise | HealthDataType.heartRateRecoveryOneMinute |
Avg, Min, Max | iOS HealthKit (iOS 16+) | - | HKQuantityTypeIdentifier.heartRateRecoveryOneMinute |
| Electrodermal Activity | Skin conductance measurements | HealthDataType.electrodermalActivity |
Sum | iOS HealthKit | - | HKQuantityTypeIdentifier.electrodermalActivity |
| Inhaler Usage | Number of puffs from an inhaler | HealthDataType.inhalerUsage |
Sum | iOS HealthKit | - | HKQuantityTypeIdentifier.inhalerUsage |
| Insulin Delivery | Amount of insulin delivered | HealthDataType.insulinDelivery |
Sum | iOS HealthKit | - | HKQuantityTypeIdentifier.insulinDelivery |
๐ด Sleep #
| Data Type | Description | Data Type | Supported Aggregation | Supported On | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|---|
| Sleep Session | Complete sleep session with sleep stages | HealthDataType.sleepSession |
- | Android Health Connect | SleepSessionRecord | - |
| Sleep Stage Record | Individual sleep stage measurement | HealthDataType.sleepStageRecord |
- | iOS HealthKit | - | HKCategoryTypeIdentifier.sleepAnalysis |
๐ฅ Nutrition #
Core & Hydration
| Data Type | Description | Data Type | Supported Aggregation | Supported On | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|---|
| Nutrition (composite) | Complete nutrition record with all nutrients | HealthDataType.nutrition |
- | Android Health Connect, iOS HealthKit | NutritionRecord | HKCorrelationType.food |
| Energy | Total energy intake from food | HealthDataType.dietaryEnergyConsumed |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.energy field) | HKQuantityTypeIdentifier.dietaryEnergyConsumed |
| Hydration/Water | Water and fluid intake | HealthDataType.hydration |
Sum | iOS HealthKit | HydrationRecord | HKQuantityTypeIdentifier.dietaryWater |
Macronutrients
| Data Type | Description | Data Type | Supported Aggregation | Supported On | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|---|
| Protein | Protein intake | HealthDataType.dietaryProtein |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.protein) | HKQuantityTypeIdentifier.dietaryProtein |
| Total Carbohydrate | Total carbs intake | HealthDataType.dietaryTotalCarbohydrate |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.carbs) | HKQuantityType Identifier.dietaryCarbohydrates |
| Total Fat | Total fat intake | HealthDataType.dietaryTotalFat |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.totalFat) | HKQuantityTypeIdentifier.dietaryFatTotal |
| Caffeine | Caffeine intake | HealthDataType.dietaryCaffeine |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.caffeine) | HKQuantityTypeIdentifier.dietaryCaffeine |
Fats
| Data Type | Description | Data Type | Supported Aggregation | Supported On | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|---|
| Saturated Fat | Saturated fat intake | HealthDataType.dietarySaturatedFat |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.saturatedFat) | HKQuantityTypeIdentifier.dietaryFatSaturated |
| Monounsaturated Fat | Monounsaturated fat intake | HealthDataType.dietaryMonounsaturatedFat |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.monounsaturatedFat) | HKQuantityTypeIdentifier.dietaryFatMonounsaturated |
| Polyunsaturated Fat | Polyunsaturated fat intake | HealthDataType.dietaryPolyunsaturatedFat |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.polyunsaturatedFat) | HKQuantityTypeIdentifier.dietaryFatPolyunsaturated |
| Cholesterol | Cholesterol intake | HealthDataType.dietaryCholesterol |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.cholesterol) | HKQuantityTypeIdentifier.dietaryCholesterol |
Fiber & Sugar
| Data Type | Description | Data Type | Supported Aggregation | Supported On | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|---|
| Dietary Fiber | Dietary fiber intake | HealthDataType.dietaryFiber |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.dietaryFiber) | HKQuantityTypeIdentifier.dietaryFiber |
| Sugar | Sugar intake | HealthDataType.dietarySugar |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.sugar) | HKQuantityTypeIdentifier.dietarySugar |
Minerals
| Data Type | Description | Data Type | Supported Aggregation | Supported On | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|---|
| Calcium | Calcium intake | HealthDataType.dietaryCalcium |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.calcium) | HKQuantityTypeIdentifier.dietaryCalcium |
| Iron | Iron intake | HealthDataType.dietaryIron |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.iron) | HKQuantityTypeIdentifier.dietaryIron |
| Magnesium | Magnesium intake | HealthDataType.dietaryMagnesium |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.magnesium) | HKQuantityTypeIdentifier.dietaryMagnesium |
| Manganese | Manganese intake | HealthDataType.dietaryManganese |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.manganese) | HKQuantityTypeIdentifier.dietaryManganese |
| Phosphorus | Phosphorus intake | HealthDataType.dietaryPhosphorus |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.phosphorus) | HKQuantityTypeIdentifier.dietaryPhosphorus |
| Potassium | Potassium intake | HealthDataType.dietaryPotassium |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.potassium) | HKQuantityTypeIdentifier.dietaryPotassium |
| Selenium | Selenium intake | HealthDataType.dietarySelenium |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.selenium) | HKQuantityTypeIdentifier.dietarySelenium |
| Sodium | Sodium intake | HealthDataType.dietarySodium |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.sodium) | HKQuantityTypeIdentifier.dietarySodium |
| Zinc | Zinc intake | HealthDataType.dietaryZinc |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.zinc) | HKQuantityTypeIdentifier.dietaryZinc |
B Vitamins
| Data Type | Description | Data Type | Supported Aggregation | Supported On | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|---|
| Thiamin (B1) | Thiamin (vitamin B1) intake | HealthDataType.dietaryThiamin |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.thiamin) | HKQuantityTypeIdentifier.dietaryThiamin |
| Riboflavin (B2) | Riboflavin (vitamin B2) | HealthDataType.dietaryRiboflavin |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.riboflavin) | HKQuantityTypeIdentifier.dietaryRiboflavin |
| Niacin (B3) | Niacin (vitamin B3) intake | HealthDataType.dietaryNiacin |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.niacin) | HKQuantityTypeIdentifier.dietaryNiacin |
| Pantothenic Acid (B5) | Pantothenic acid (vitamin B5) | HealthDataType.dietaryPantothenicAcid |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.pantothenicAcid) | HKQuantityTypeIdentifier.dietaryPantothenicAcid |
| Vitamin B6 | Vitamin B6 intake | HealthDataType.dietaryVitaminB6 |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.vitaminB6) | HKQuantityTypeIdentifier.dietaryVitaminB6 |
| Biotin (B7) | Biotin (vitamin B7) intake | HealthDataType.dietaryBiotin |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.biotin) | HKQuantityTypeIdentifier.dietaryBiotin |
| Folate (B9) | Folate (vitamin B9) intake | HealthDataType.dietaryFolate |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.folate) | HKQuantityTypeIdentifier.dietaryFolate |
| Vitamin B12 | Vitamin B12 intake | HealthDataType.dietaryVitaminB12 |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.vitaminB12) | HKQuantityTypeIdentifier.dietaryVitaminB12 |
Other Vitamins
| Data Type | Description | Data Type | Supported Aggregation | Supported On | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|---|
| Vitamin A | Vitamin A intake | HealthDataType.dietaryVitaminA |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.vitaminA) | HKQuantityTypeIdentifier.dietaryVitaminA |
| Vitamin C | Vitamin C intake | HealthDataType.dietaryVitaminC |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.vitaminC) | HKQuantityTypeIdentifier.dietaryVitaminC |
| Vitamin D | Vitamin D intake | HealthDataType.dietaryVitaminD |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.vitaminD) | HKQuantityTypeIdentifier.dietaryVitaminD |
| Vitamin E | Vitamin E intake | HealthDataType.dietaryVitaminE |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.vitaminE) | HKQuantityTypeIdentifier.dietaryVitaminE |
| Vitamin K | Vitamin K intake | HealthDataType.dietaryVitaminK |
Sum | iOS HealthKit | NutritionRecord (NutritionRecord.vitaminK) | HKQuantityTypeIdentifier.dietaryVitaminK |
Alcohol
| Data Type | Description | Data Type | Supported Aggregation | Supported On | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|---|
| Alcoholic Beverages | Count of alcoholic drinks | HealthDataType.alcoholicBeverages |
Sum | iOS HealthKit | - | HKQuantityTypeIdentifier.numberOfAlcoholicBeverages |
๐ง Wellness #
| Data Type | Description | Data Type | Supported Aggregation | Supported On | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|---|
| Mindfulness Session | Meditation and mindfulness sessions | HealthDataType.mindfulnessSession |
Sum | Android Health Connect, iOS HealthKit | MindfulnessSessionRecord | HKCategoryTypeIdentifier.mindfulSession |
๐ชท Cycle Tracking #
| Data Type | Description | Data Type | Supported Aggregation | Supported On | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|---|
| Cervical Mucus | Cervical mucus observations for fertility | HealthDataType.cervicalMucus |
- | Android Health Connect, iOS HealthKit | CervicalMucusRecord | HKCategoryTypeIdentifier.cervicalMucusQuality |
| Basal Body Temperature | Basal body temperature | HealthDataType.basalBodyTemperature |
Avg, Min, Max | Android Health Connect, iOS HealthKit | BasalBodyTemperatureRecord | HKQuantityTypeIdentifier.basalBodyTemperature |
| Menstruation Flow | Menstrual flow intensity | HealthDataType.menstrualFlow |
- | Android Health Connect, iOS HealthKit | MenstruationFlowRecord | HKCategoryTypeIdentifier.menstrualFlow |
| Ovulation Test | Ovulation test result | HealthDataType.ovulationTest |
- | Android Health Connect, iOS HealthKit | OvulationTestRecord | HKCategoryTypeIdentifier.ovulationTestResult |
| Intermenstrual Bleeding | Intermenstrual bleeding spotting | HealthDataType.intermenstrualBleeding |
- | iOS HealthKit | - | HKCategoryTypeIdentifier.persistentIntermenstrualBleeding |
| Progesterone Test | Progesterone test result | HealthDataType.progesteroneTest |
- | iOS HealthKit | - | HKCategoryTypeIdentifier.progesteroneTestResult |
| Pregnancy Test | Pregnancy test result | HealthDataType.pregnancyTest |
- | iOS HealthKit | - | HKCategoryTypeIdentifier.pregnancyTestResult |
| Pregnancy | Pregnancy status | HealthDataType.pregnancy |
- | iOS HealthKit | - | HKCategoryTypeIdentifier.pregnancy |
| Lactation | Lactation status | HealthDataType.lactation |
- | iOS HealthKit | - | HKCategoryTypeIdentifier.lactation |
| Contraceptive | Contraceptive usage | HealthDataType.contraceptive |
- | iOS HealthKit | - | HKCategoryTypeIdentifier.contraceptive |
| Infrequent Menstrual Cycle Event | Infrequent menstrual cycle event | HealthDataType.infrequentMenstrualCycleEvent |
- | iOS HealthKit (iOS 16+) | - | HKCategoryTypeIdentifier.infrequentMenstrualCycles |
| Irregular Menstrual Cycle Event | Irregular menstrual cycle event | HealthDataType.irregularMenstrualCycleEvent |
- | iOS HealthKit (iOS 16+) | - | HKCategoryTypeIdentifier.irregularMenstrualCycles |
| Persistent Intermenstrual Bleeding | Persistent intermenstrual bleeding event | HealthDataType.persistentIntermenstrualBleedingEvent |
- | iOS HealthKit (iOS 16+) | - | HKCategoryTypeIdentifier.persistentIntermenstrualBleeding |
| Prolonged Menstrual Period Event | Prolonged menstrual period event | HealthDataType.prolongedMenstrualPeriodEvent |
- | iOS HealthKit (iOS 16+) | - | HKCategoryTypeIdentifier.prolongedMenstrualPeriods |
๐ References #
๐ Migration Guides #
๐ค Contributing #
Contributions are welcome! See our GitHub Issues to report bugs or request features.
๐ License #
This project is licensed under the Apache 2.0 License - see the LICENSE file for details.









