health_connector 3.0.0
health_connector: ^3.0.0 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 sync, and privacy-first architecture.
๐ Table of Contents #
-
โฌ๏ธ Migration Guide v2.x.x โ v3.0.0
-
- ๐ Permission Management
- ๐ Reading Health Data
- โ๏ธ Writing Health Data
- ๐ Updating Health Records
- ๐๏ธ Deleting Health Records
- โ Aggregating Health Data
- ๐ Incremental Sync
- โ๏ธ Feature Management
- ๐ท๏ธ Health Data Type Categories
- โ ๏ธ Error Handling
- ๐ Logging
- โ Troubleshooting & FAQ
- ๐ฏ Real-World Use Cases
๐ฎ 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 |
|---|---|---|---|---|
| [Permission Request] | [Read Data] | [Write Data] | [Delete Data] | [Aggregate Data] |
| [Permission Request] | [Read Data] | [Write Data] | [Delete Data] | [Aggregate Data] |
๐ 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 #
| Platform | Minimum OS Version | Language Version |
|---|---|---|
| Android | API 26+ | Kotlin 2.1.0 |
| iOS | โฅ15.0 | Swift 5.9 |
Note: Users currently using Swift 5.0+ (up to 5.9) or Kotlin 2.0+ (up to 2.1) will find updating their Flutter project to Swift 5.9 and Kotlin 2.1 straightforward, as these versions are compatible.
๐ฆ 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. This is required because registerForActivityResult is only available
in ComponentActivity and its subclasses.
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 = [
_createStepsRecord(now.subtract(Duration(hours: 3)), 1500),
_createStepsRecord(now.subtract(Duration(hours: 2)), 2000),
_createStepsRecord(now.subtract(Duration(hours: 1)), 1800),
];
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');
}
// Helper to create step records
StepsRecord _createStepsRecord(DateTime time, int steps) {
return StepsRecord(
startTime: time,
endTime: time.add(Duration(hours: 1)),
count: Number(steps),
metadata: Metadata.automaticallyRecorded(
device: Device.fromType(DeviceType.phone),
),
);
}
What's Next? Check out the Developer Guide for full API documentation, error handling, and advanced features.
๐ Developer Guide #
๐ Permission Management #
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('โ
Granted');
case PermissionStatus.denied:
print('โ Denied');
case PermissionStatus.unknown:
print('โ Unknown (iOS read)');
}
Workaround: Detecting iOS Read 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 likely granted
} on AuthorizationException {
return false; // Explicitly denied
} catch (_) {
return false; // Handle other errors as needed
}
}
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.
Request Permissions
final permissions = [
HealthDataType.steps.readPermission,
HealthDataType.steps.writePermission,
HealthDataType.weight.readPermission,
HealthPlatformFeature.readHealthDataInBackground.permission,
];
final results = await connector.requestPermissions(permissions);
// Process results
for (final result in results) {
switch (result.status) {
case PermissionStatus.granted:
print('โ
${result.permission}');
case PermissionStatus.denied:
print('โ ${result.permission}');
case PermissionStatus.unknown:
print('โ ${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 granted = await connector.getGrantedPermissions();
for (final p in granted) {
print('โ
Granted: ${p.dataType} (${p.accessType})');
}
} 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');
}
๐ Reading Health Data #
Read by ID
final record = await connector.readRecord(
HealthDataType.steps.readRecord(HealthRecordId('record-id')),
);
if (record != null) {
print('๐ Found: ${record.count.value} steps');
}
Read by Time Range
final response = await connector.readRecords(
HealthDataType.steps.readInTimeRange(
startTime: DateTime.now().subtract(Duration(days: 7)),
endTime: DateTime.now(),
pageSize: 100,
),
);
print('๐ Found ${response.records.length} records');
for (final record in response.records) {
print('${record.count.value} steps on ${record.startTime}');
}
Historical Data Access: Android Health Connect defaults to 30 daysโrequest
HealthPlatformFeature.readHealthDataHistorypermission for older data. iOS HealthKit has no restrictions.
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
var request = HealthDataType.steps.readInTimeRange(
startTime: DateTime.now().subtract(Duration(days: 30)),
endTime: DateTime.now(),
pageSize: 100,
);
final allRecords = <StepsRecord>[];
// Fetch all pages
while (true) {
final response = await connector.readRecords(request);
allRecords.addAll(response.records.cast<StepsRecord>());
// Check if there are more pages
if (response.nextPageRequest == null) break;
request = response.nextPageRequest!;
}
print('๐ Total: ${allRecords.length} records');
โ๏ธ Writing Health Data #
Write Single Record
final record = StepsRecord(
id: HealthRecordId.none, // Must be .none for new records
startTime: DateTime.now().subtract(Duration(hours: 1)),
endTime: DateTime.now(),
count: Number(5000),
metadata: Metadata.automaticallyRecorded(
device: Device.fromType(DeviceType.phone),
),
);
final recordId = await connector.writeRecord(record);
print('โ
Saved: $recordId');
Batch Write Multiple Records
All records succeed or all fail together:
// Helper to create step records
StepsRecord _createSteps(DateTime time, int steps) => StepsRecord(
id: HealthRecordId.none,
startTime: time,
endTime: time.add(Duration(hours: 1)),
count: Number(steps),
metadata: Metadata.automaticallyRecorded(
device: Device.fromType(DeviceType.phone),
),
);
final now = DateTime.now();
final records = [
_createSteps(now.subtract(Duration(hours: 3)), 1500),
_createSteps(now.subtract(Duration(hours: 2)), 2000),
_createSteps(now.subtract(Duration(hours: 1)), 1800),
];
final ids = await connector.writeRecords(records);
print('โ
Wrote ${ids.length} records');
๐ Updating Health Records #
iOS Limitation: HealthKit uses an immutable data modelโrecords cannot be updated, only deleted and recreated.
Update Single Record (Android Health Connect only)
final record = await connector.readRecord(
HealthDataType.steps.readRecord(HealthRecordId('record-id')),
);
if (record != null) {
await connector.updateRecord(
record.copyWith(count: Number(record.count.value + 500)),
);
print('โ
Record updated');
}
iOS Workaround: Delete + Recreate
// Delete existing
await connector.deleteRecords(
HealthDataType.steps.deleteByIds([existingRecord.id]),
);
// Write new record with updated values
final newRecord = existingRecord.copyWith(
id: HealthRecordId.none,
count: Number(newValue),
);
final newId = await connector.writeRecord(newRecord);
// โ ๏ธ Note: ID changes after recreation
Batch Update (Android Health Connect only)
Update multiple records atomicallyโall succeed or all fail.
// Fetch records to update
final response = await connector.readRecords(
HealthDataType.steps.readInTimeRange(
startTime: DateTime.now().subtract(Duration(days: 7)),
endTime: DateTime.now(),
),
);
// Apply updates
final updated = response.records.map((r) =>
r.copyWith(count: Number(r.count.value + 100))
).toList();
await connector.updateRecords(updated);
print('โ
Updated ${updated.length} records');
๐๏ธ Deleting Health Records #
Note: Apps can only delete records they createdโplatform security restriction.
Delete by IDs
try {
await connector.deleteRecords(
HealthDataType.steps.deleteByIds([
HealthRecordId('id-1'),
HealthRecordId('id-2'),
]),
);
print('โ
Deleted');
} on AuthorizationException {
print('โ Cannot delete records from other apps');
}
Delete by Time Range
await connector.deleteRecords(
HealthDataType.steps.deleteInTimeRange(
startTime: DateTime.now().subtract(Duration(days: 7)),
endTime: DateTime.now(),
),
);
๐ Aggregating Health Data #
Example: Sum
final now = DateTime.now();
final thirtyDaysAgo = now.subtract(Duration(days: 30));
final response = await connector.aggregate(
HealthDataType.steps.aggregateSum(
startTime: thirtyDaysAgo,
endTime: now,
),
);
print('Total steps: ${response.value.value}');
final avg = await connector.aggregate(
HealthDataType.weight.aggregateAvg(
startTime: thirtyDaysAgo,
endTime: now,
),
);
print('Avg: ${avg.value.inKilograms} kg');
final min = await connector.aggregate(
HealthDataType.weight.aggregateMin(
startTime: thirtyDaysAgo,
endTime: now,
),
);
print('Min: ${min.value.inKilograms} kg');
final max = await connector.aggregate(
HealthDataType.weight.aggregateMax(
startTime: thirtyDaysAgo,
endTime: now,
),
);
print('Max: ${max.value.inKilograms} kg');
๐ Incremental Sync #
Incremental sync allows you to retrieve only health data that has changed since your last sync, reducing bandwidth usage and improving performance.
How It Works
- Initial Sync: Pass
nullassyncTokento get initial sync token - Incremental Sync: Use the returned
nextSyncTokenfor subsequent syncs - Change Tracking: Automatically tracks additions, updates, and deletions
Example: Basic Incremental Sync
import 'package:health_connector/health_connector.dart';
final storage = LocalTokenStorage(); // f.e. SharedPreferences
// 1. Initial setup - set initial sync checkpoint
Future<void> setInitialSyncCheckpoint() async {
final connector = await HealthConnector.create();
final result = await connector.synchronize(
dataTypes: [HealthDataType.steps, HealthDataType.heartRate],
syncToken: null,
);
final initialSyncToken = result.nextSyncToken;
// Save token
await storage.saveToken(initialSyncToken.toJson());
print('โ
Initial setup complete');
}
// 2. Incremental sync - get changes
Future<void> performIncrementalSync() async {
final connector = await HealthConnector.create();
// Load saved token
final tokenJson = await storage.loadToken();
if (tokenJson == null) {
print('โ ๏ธ No token found, setting sync checkpoint instead');
await setInitialSyncCheckpoint();
return;
}
final token = HealthDataSyncToken.fromJson(tokenJson);
final result = await connector.synchronize(
dataTypes: [HealthDataType.steps, HealthDataType.heartRate],
syncToken: token,
);
// Process changes
print('New/Updated records: ${result.upsertedRecords.length}');
print('Deleted record IDs: ${result.deletedRecordIds.length}');
print('Has more pages: ${result.hasMore}');
// Update your local database with changes
for (final record in result.upsertedRecords) {
// await database.upsert(record);
}
for (final id in result.deletedRecordIds) {
// await database.delete(id);
}
// Save new token
await storage.saveToken(result.nextSyncToken.toJson());
}
Pagination Support
var token = savedToken;
final allChanges = <HealthRecord>[];
// Fetch all pages
while (true) {
final result = await connector.synchronize(
dataTypes: [HealthDataType.steps],
syncToken: token,
);
allChanges.addAll(result.upsertedRecords);
if (!result.hasMore) break;
token = result.nextSyncToken;
}
// Save new token
await storage.saveToken(result.nextSyncToken.toJson());
โ๏ธ Feature Management #
Platform Behavior: iOS HealthKit features are always available (built into iOS). Android Health Connect features depend on app versionโcheck
getFeatureStatus()before requesting permissions.
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');
}
โ ๏ธ 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 | Platform | Exception Type | Description & Causes | Recovery Strategy |
|---|---|---|---|---|
permissionNotGranted |
Both | AuthorizationException |
Permission denied, revoked, or not determined. | Request permissions or guide user to settings. |
permissionNotDeclared |
All | ConfigurationException |
Missing required permission in AndroidManifest.xml or Info.plist. |
Developer Error: Add missing permissions to your app configuration. |
healthServiceUnavailable |
All | HealthServiceUnavailableException |
Device doesn't support Health Connect (Android) or HealthKit (iPad). | Check getHealthPlatformStatus(). Gracefully disable health features. |
healthServiceRestricted |
All | HealthServiceUnavailableException |
Health data access restricted by system policy (e.g. parental controls). | Gracefully disable health features and inform the user. |
healthServiceNotInstalledOrUpdateRequired |
Android | HealthServiceUnavailableException |
Health Connect app is missing or needs an update. | Prompt user to install/update via launchHealthAppPageInAppStore(). |
healthServiceDatabaseInaccessible |
iOS | HealthServiceException |
Device is locked and health database is encrypted/inaccessible. | Wait for device unlock or notify user to unlock their device. |
ioError |
Android | HealthServiceException |
Device storage I/O failed while reading/writing records. | Retry operation with exponential backoff. |
remoteError |
Android | HealthServiceException |
IPC communication with the underlying health service failed. | Retry operation; usually a temporary system glitch. |
rateLimitExceeded |
Android | HealthServiceException |
API request quota exhausted. | Wait and retry later. Implement exponential backoff. |
dataSyncInProgress |
Android | HealthServiceException |
Health Connect is currently syncing data; operations locked. | Retry after a short delay or show a "Syncing..." status. |
invalidArgument |
All | InvalidArgumentException |
Invalid parameter, malformed record, or expired usage of a token. | Validate input. For expired sync tokens, restart sync with syncToken: null. |
unsupportedOperation |
All | UnsupportedOperationException |
The requested operation is not supported on this platform/version. | Check capability with getFeatureStatus() before calling. |
unknownError |
All | UnknownException |
An unclassified internal system error occurred. | Log the error details for debugging. |
Example: Robust Error Handling
try {
await connector.writeRecord(record);
} on AuthorizationException catch (e) {
// 1. Permission Issues
// The user likely revoked permission in system settings.
print('๐ Authorization failed: ${e.message}');
// Suggested: Show a dialog explaining why permission is needed,
// then link to system settings.
_showPermissionExplanationDialog();
} on HealthServiceUnavailableException catch (e) {
// 2. Service Availability Issues
// Health Connect missing (Android) or device unsupported (iOS).
print('โ Service unavailable: ${e.code}');
if (e.code == HealthConnectorErrorCode.healthServiceNotInstalledOrUpdateRequired) {
// Android: Prompt user to install/update Health Connect
_promptToInstallHealthConnect();
} else {
// iOS/Android: Device capability missing. Disable health features.
_disableHealthIntegration();
}
} on HealthServiceException catch (e) {
// 3. Runtime/Operational Errors
switch (e.code) {
case HealthConnectorErrorCode.rateLimitExceeded:
// API quota exhausted. Wait and retry with backoff.
print('โณ Rate limit exceeded. Retrying in 5s...');
await Future.delayed(Duration(seconds: 5));
_retryWrite();
break;
case HealthConnectorErrorCode.dataSyncInProgress:
// Health Connect is busy syncing.
print('๐ Syncing... please wait.');
break;
case HealthConnectorErrorCode.remoteError:
case HealthConnectorErrorCode.ioError:
// Temporary system glitches. Retry once or twice.
print('๐ฅ Transient error: ${e.message}');
_retryWithBackoff();
break;
default:
print('โ ๏ธ Health Service Warning: ${e.message}');
}
} on InvalidArgumentException catch (e) {
// 4. Input Errors
print('โ ๏ธ Invalid data or expired token: ${e.message}');
} catch (e, stack) {
// 5. Unknown/Unexpected Errors
print('โ๏ธ Unexpected system error: $e');
// reportToCrashlytics(e, stack);
}
๐ Logging & Privacy #
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')),
],
),
),
);
๐ง Troubleshooting & FAQ #
| Issue / Question | Platform / Context | Solution / Answer |
|---|---|---|
HealthServiceUnavailableException |
iOS HealthKit | Add HealthKit capability in Xcode โ Signing & Capabilities |
HealthServiceUnavailableException |
Android Health Connect | Device doesn't support Health Connect (requires Android 8.0+) |
HealthServiceUnavailableException |
Android Health Connect | Check getHealthPlatformStatus() and call launchHealthAppPageInAppStore() to open Play Store |
ConfigurationException |
Android Health Connect | Add required permissions to AndroidManifest.xml |
ConfigurationException |
iOS HealthKit | Add NSHealthShareUsageDescription and NSHealthUpdateUsageDescription to Info.plist |
Why do iOS read permissions return unknown? |
iOS HealthKit | Apple hides read permission status to protect privacy โ apps cannot infer if a user has health data |
What's the difference between heartRateSeriesRecord and heartRateMeasurementRecord? |
Cross-platform | Android uses series records (multiple samples in one record); iOS uses individual measurement records |
| Can I read health data from other apps? | Both platforms | Yes โ with user permission, you can read data from all sources (apps, devices, manual entries) |
| Can I modify/delete data from other apps? | Both platforms | No โ apps can only modify or delete records they created (platform security restriction) |
๐ฏ Real-World Use Cases #
๐ Fitness Dashboard
// Get daily summary: steps & calories
Future<Map<String, double>> getDailySummary(HealthConnector connector) async {
final now = DateTime.now();
final today = DateTime(now.year, now.month, now.day);
final tomorrow = today.add(Duration(days: 1));
final steps = await connector.aggregate(
HealthDataType.steps.aggregateSum(startTime: today, endTime: tomorrow),
);
final calories = await connector.aggregate(
HealthDataType.activeEnergyBurned.aggregateSum(startTime: today, endTime: tomorrow),
);
return {
'steps': steps.value.value,
'calories': calories.value.inKilocalories,
};
}
โค๏ธ Vitals Monitor
Future<void> logVitals(HealthConnector connector) async {
final weekAgo = DateTime.now().subtract(Duration(days: 7));
final now = DateTime.now();
// 1. Get latest weight
final weight = await connector.readRecords(
HealthDataType.weight.readInTimeRange(
startTime: weekAgo, endTime: now, pageSize: 1,
),
);
if (weight.records.isNotEmpty) {
print('โ๏ธ Latest weight: ${(weight.records.first as WeightRecord).weight.inKilograms} kg');
}
// 2. Get avg resting heart rate
final hr = await connector.aggregate(
HealthDataType.restingHeartRate.aggregateAvg(startTime: weekAgo, endTime: now),
);
print('๐ Avg Resting HR: ${hr.value.inPerMinute} bpm');
}
๐ฅ Nutrition Tracker
Future<void> logLunch(HealthConnector connector) async {
final entry = NutritionRecord(
id: HealthRecordId.none,
startTime: DateTime.now().subtract(Duration(minutes: 30)),
endTime: DateTime.now(),
name: 'Grilled Chicken Salad',
energy: Energy.kilocalories(450),
protein: Mass.grams(40),
totalCarbohydrate: Mass.grams(12),
totalFat: Mass.grams(15),
metadata: Metadata.manualEntry(),
);
await connector.writeRecord(entry);
print('โ
Meal logged');
}
๐ References #
๐ Supported Health Data Types #
๐ Activity
General Activity
| Data Type | Description | Data Type | Supported Aggregation | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|
| Steps | Number of steps taken | HealthDataType.steps |
Sum | StepsRecord | HKQuantityTypeIdentifier.stepCount |
| Active Energy Burned | Energy burned through active movement | HealthDataType.activeEnergyBurned |
Sum | ActiveEnergyBurnedRecord | HKQuantityTypeIdentifier.activeEnergyBurned |
| Floors Climbed | Number of floors (flights of stairs) climbed | HealthDataType.floorsClimbed |
Sum | FloorsClimbedRecord | HKQuantityTypeIdentifier.flightsClimbed |
| Sexual Activity | Sexual activity tracking | HealthDataType.sexualActivity |
- | SexualActivityRecord | HKCategoryTypeIdentifier.sexualActivity |
| Wheelchair Pushes | Number of wheelchair pushes | HealthDataType.wheelchairPushes |
Sum | WheelchairPushesRecord | HKQuantityTypeIdentifier.pushCount |
| Cycling Cadence | Cycling pedaling cadence | HealthDataType.cyclingPedalingCadence |
Avg, Min, Max | CyclingPedalingCadenceRecord | HKQuantityTypeIdentifier.cyclingCadence |
| Total Energy Burned | Total energy burned (active + basal) | HealthDataType.totalEnergyBurned |
Sum | TotalEnergyBurnedRecord | - |
| Basal Energy Burned | Energy burned by basal metabolism | HealthDataType.basalEnergyBurned |
Sum | - | HKQuantityTypeIdentifier.basalEnergyBurned |
Distance Types
| Data Type | Description | Data Type | Supported Aggregation | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|
| Distance (generic) | Generic distance traveled | HealthDataType.distance |
Sum | DistanceRecord | - |
| Walking/Running Distance | Distance covered by walking or running | HealthDataType.walkingRunningDistance |
Sum | - | HKQuantityTypeIdentifier.distanceWalkingRunning |
| Cycling Distance | Distance covered by cycling | HealthDataType.cyclingDistance |
Sum | - | HKQuantityTypeIdentifier.distanceCycling |
| Swimming Distance | Distance covered by swimming | HealthDataType.swimmingDistance |
Sum | - | HKQuantityTypeIdentifier.distanceSwimming |
| Wheelchair Distance | Distance covered using a wheelchair | HealthDataType.wheelchairDistance |
Sum | - | HKQuantityTypeIdentifier.distanceWheelchair |
| Downhill Snow Sports Distance | Distance covered during downhill snow sports | HealthDataType.downhillSnowSportsDistance |
Sum | - | HKQuantityTypeIdentifier.distanceDownhillSnowSports |
| Cross Country Skiing Distance | Distance covered during cross country skiing | HealthDataType.crossCountrySkiingDistance |
Sum | - | HKQuantityTypeIdentifier.distanceCrossCountrySkiing |
| Paddle Sports Distance | Distance covered during paddle sports | HealthDataType.paddleSportsDistance |
Sum | - | HKQuantityTypeIdentifier.distancePaddleSports |
| Rowing Distance | Distance covered during rowing | HealthDataType.rowingDistance |
Sum | - | HKQuantityTypeIdentifier.distanceRowing |
| Skating Sports Distance | Distance covered during skating sports | HealthDataType.skatingSportsDistance |
Sum | - | HKQuantityTypeIdentifier.distanceSkatingSports |
| Six Minute Walk Test Distance | Distance covered during 6-minute walk test | HealthDataType.sixMinuteWalkTestDistance |
Sum | - | HKQuantityTypeIdentifier.sixMinuteWalkTestDistance |
Speed Types
| Data Type | Description | Data Type | Supported Aggregation | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|
| Speed Series | Speed measurements over time | HealthDataType.speedSeries |
- | SpeedRecord | - |
| Walking Speed | Walking speed measurement | HealthDataType.walkingSpeed |
- | - | HKQuantityTypeIdentifier.walkingSpeed |
| Running Speed | Running speed measurement | HealthDataType.runningSpeed |
- | - | HKQuantityTypeIdentifier.runningSpeed |
| Stair Ascent Speed | Speed while climbing stairs | HealthDataType.stairAscentSpeed |
- | - | HKQuantityTypeIdentifier.stairAscentSpeed |
| Stair Descent Speed | Speed while descending stairs | HealthDataType.stairDescentSpeed |
- | - | HKQuantityTypeIdentifier.stairDescentSpeed |
Power Types
| Data Type | Description | Data Type | Supported Aggregation | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|
| Power Series | Power measurements over time | HealthDataType.powerSeries |
Avg, Min, Max | PowerRecord | - |
| Cycling Power | Power output during cycling | HealthDataType.cyclingPower |
Avg, Min, Max | - | HKQuantityTypeIdentifier.cyclingPower |
Exercise Sessions
| Data Type | Description | Data Type | Supported Aggregation | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|
| Exercise Session | Complete workout session with exercise type and stats | HealthDataType.exerciseSession |
Duration | 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 | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|
| Weight | Body weight measurement | HealthDataType.weight |
Avg, Min, Max | WeightRecord | HKQuantityTypeIdentifier.bodyMass |
| Height | Body height measurement | HealthDataType.height |
Avg, Min, Max | HeightRecord | HKQuantityTypeIdentifier.height |
| Body Fat Percentage | Percentage of body fat | HealthDataType.bodyFatPercentage |
Avg, Min, Max | BodyFatRecord | HKQuantityTypeIdentifier.bodyFatPercentage |
| Lean Body Mass | Mass of body excluding fat | HealthDataType.leanBodyMass |
Avg, Min, Max | LeanBodyMassRecord | HKQuantityTypeIdentifier.leanBodyMass |
| Body Temperature | Core body temperature | HealthDataType.bodyTemperature |
Avg, Min, Max | BodyTemperatureRecord | HKQuantityTypeIdentifier.bodyTemperature |
| Body Water Mass | Mass of body water | HealthDataType.bodyWaterMass |
Avg, Min, Max | BodyWaterMassRecord | - |
| Bone Mass | Mass of bone mineral | HealthDataType.boneMass |
Avg, Min, Max | BoneMassRecord | - |
| Body Mass Index | Body Mass Index (BMI) | HealthDataType.bodyMassIndex |
Avg, Min, Max | - | HKQuantityTypeIdentifier.bodyMassIndex |
| Waist Circumference | Waist circumference measurement | HealthDataType.waistCircumference |
Avg, Min, Max | - | HKQuantityTypeIdentifier.waistCircumference |
โค๏ธ Vitals
| Data Type | Description | Data Type | Supported Aggregation | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|
| Heart Rate Series | Heart rate measurements over time | HealthDataType.heartRateSeries |
Avg, Min, Max | HeartRateRecord | - |
| Heart Rate Measurement | Single heart rate measurement | HealthDataType.heartRate |
Avg, Min, Max | - | HKQuantityTypeIdentifier.heartRate |
| Resting Heart Rate | Heart rate while at rest | HealthDataType.restingHeartRate |
Avg, Min, Max | RestingHeartRateRecord | HKQuantityTypeIdentifier.restingHeartRate |
| Blood Pressure | Systolic and diastolic blood pressure | HealthDataType.bloodPressure |
Avg, Min, Max | BloodPressureRecord | HKCorrelationTypeIdentifier.bloodPressure |
| Systolic Blood Pressure | Upper blood pressure value | HealthDataType.systolicBloodPressure |
Avg, Min, Max | - | HKQuantityTypeIdentifier.bloodPressureSystolic |
| Diastolic Blood Pressure | Lower blood pressure value | HealthDataType.diastolicBloodPressure |
Avg, Min, Max | - | HKQuantityTypeIdentifier.bloodPressureDiastolic |
| Oxygen Saturation | Blood oxygen saturation percentage | HealthDataType.oxygenSaturation |
Avg, Min, Max | OxygenSaturationRecord | HKQuantityTypeIdentifier.oxygenSaturation |
| Respiratory Rate | Breathing rate (breaths per minute) | HealthDataType.respiratoryRate |
Avg, Min, Max | RespiratoryRateRecord | HKQuantityTypeIdentifier.respiratoryRate |
| VOโ Max | Maximum oxygen consumption | HealthDataType.vo2Max |
Avg, Min, Max | Vo2MaxRecord | HKQuantityTypeIdentifier.vo2Max |
| Blood Glucose | Blood glucose concentration | HealthDataType.bloodGlucose |
Avg, Min, Max | BloodGlucoseRecord | HKQuantityTypeIdentifier.bloodGlucose |
| HRV RMSSD | Heart Rate Variability (RMSSD) | HealthDataType.heartRateVariabilityRMSSD |
- | HeartRateVariabilityRMSSDRecord | - |
| HRV SDNN | Heart Rate Variability (SDNN) | HealthDataType.heartRateVariabilitySDNN |
- | - | HKQuantityTypeIdentifier.heartRateVariabilitySDNN |
๐ด Sleep
| Data Type | Description | Data Type | Supported Aggregation | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|
| Sleep Session | Complete sleep session with sleep stages | HealthDataType.sleepSession |
- | SleepSessionRecord | - |
| Sleep Stage Record | Individual sleep stage measurement | HealthDataType.sleepStageRecord |
- | - | HKCategoryTypeIdentifier.sleepAnalysis |
๐ Nutrition
Core & Hydration
| Data Type | Description | Data Type | Supported Aggregation | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|
| Nutrition (composite) | Complete nutrition record with macros and micronutrients | HealthDataType.nutrition |
- | NutritionRecord | HKCorrelationType.food |
| Energy | Total energy intake from food | HealthDataType.dietaryEnergyConsumed (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.energy field) | HKQuantityTypeIdentifier.dietaryEnergyConsumed |
| Hydration/Water | Water and fluid intake | HealthDataType.hydration |
Sum | HydrationRecord | HKQuantityTypeIdentifier.dietaryWater |
Macronutrients
| Data Type | Description | Data Type | Supported Aggregation | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|
| Protein | Protein intake | HealthDataType.dietaryProtein (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.protein) | HKQuantityTypeIdentifier.dietaryProtein |
| Total Carbohydrate | Total carbs intake | HealthDataType.dietaryTotalCarbohydrate (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.carbs) | HKQuantityType Identifier.dietaryCarbohydrates |
| Total Fat | Total fat intake | HealthDataType.dietaryTotalFat (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.totalFat) | HKQuantityTypeIdentifier.dietaryFatTotal |
| Caffeine | Caffeine intake | HealthDataType.dietaryCaffeine (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.caffeine) | HKQuantityTypeIdentifier.dietaryCaffeine |
Fats
| Data Type | Description | Data Type | Supported Aggregation | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|
| Saturated Fat | Saturated fat intake | HealthDataType.dietarySaturatedFat (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.saturatedFat) | HKQuantityTypeIdentifier.dietaryFatSaturated |
| Monounsaturated Fat | Monounsaturated fat intake | HealthDataType.dietaryMonounsaturatedFat (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.monounsaturatedFat) | HKQuantityTypeIdentifier.dietaryFatMonounsaturated |
| Polyunsaturated Fat | Polyunsaturated fat intake | HealthDataType.dietaryPolyunsaturatedFat (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.polyunsaturatedFat) | HKQuantityTypeIdentifier.dietaryFatPolyunsaturated |
| Cholesterol | Cholesterol intake | HealthDataType.dietaryCholesterol (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.cholesterol) | HKQuantityTypeIdentifier.dietaryCholesterol |
Fiber & Sugar
| Data Type | Description | Data Type | Supported Aggregation | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|
| Dietary Fiber | Dietary fiber intake | HealthDataType.dietaryFiber (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.dietaryFiber) | HKQuantityTypeIdentifier.dietaryFiber |
| Sugar | Sugar intake | HealthDataType.dietarySugar (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.sugar) | HKQuantityTypeIdentifier.dietarySugar |
Minerals
| Data Type | Description | Data Type | Supported Aggregation | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|
| Calcium | Calcium intake | HealthDataType.dietaryCalcium (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.calcium) | HKQuantityTypeIdentifier.dietaryCalcium |
| Iron | Iron intake | HealthDataType.dietaryIron (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.iron) | HKQuantityTypeIdentifier.dietaryIron |
| Magnesium | Magnesium intake | HealthDataType.dietaryMagnesium (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.magnesium) | HKQuantityTypeIdentifier.dietaryMagnesium |
| Manganese | Manganese intake | HealthDataType.dietaryManganese (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.manganese) | HKQuantityTypeIdentifier.dietaryManganese |
| Phosphorus | Phosphorus intake | HealthDataType.dietaryPhosphorus (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.phosphorus) | HKQuantityTypeIdentifier.dietaryPhosphorus |
| Potassium | Potassium intake | HealthDataType.dietaryPotassium (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.potassium) | HKQuantityTypeIdentifier.dietaryPotassium |
| Selenium | Selenium intake | HealthDataType.dietarySelenium (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.selenium) | HKQuantityTypeIdentifier.dietarySelenium |
| Sodium | Sodium intake | HealthDataType.dietarySodium (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.sodium) | HKQuantityTypeIdentifier.dietarySodium |
| Zinc | Zinc intake | HealthDataType.dietaryZinc (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.zinc) | HKQuantityTypeIdentifier.dietaryZinc |
B Vitamins
| Data Type | Description | Data Type | Supported Aggregation | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|
| Thiamin (B1) | Thiamin (vitamin B1) intake | HealthDataType.dietaryThiamin (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.thiamin) | HKQuantityTypeIdentifier.dietaryThiamin |
| Riboflavin (B2) | Riboflavin (vitamin B2) | HealthDataType.dietaryRiboflavin (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.riboflavin) | HKQuantityTypeIdentifier.dietaryRiboflavin |
| Niacin (B3) | Niacin (vitamin B3) intake | HealthDataType.dietaryNiacin (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.niacin) | HKQuantityTypeIdentifier.dietaryNiacin |
| Pantothenic Acid (B5) | Pantothenic acid (vitamin B5) | HealthDataType.dietaryPantothenicAcid (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.pantothenicAcid) | HKQuantityTypeIdentifier.dietaryPantothenicAcid |
| Vitamin B6 | Vitamin B6 intake | HealthDataType.dietaryVitaminB6 (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.vitaminB6) | HKQuantityTypeIdentifier.dietaryVitaminB6 |
| Biotin (B7) | Biotin (vitamin B7) intake | HealthDataType.dietaryBiotin (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.biotin) | HKQuantityTypeIdentifier.dietaryBiotin |
| Folate (B9) | Folate (vitamin B9) intake | HealthDataType.dietaryFolate (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.folate) | HKQuantityTypeIdentifier.dietaryFolate |
| Vitamin B12 | Vitamin B12 intake | HealthDataType.dietaryVitaminB12 (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.vitaminB12) | HKQuantityTypeIdentifier.dietaryVitaminB12 |
Other Vitamins
| Data Type | Description | Data Type | Supported Aggregation | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|
| Vitamin A | Vitamin A intake | HealthDataType.dietaryVitaminA (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.vitaminA) | HKQuantityTypeIdentifier.dietaryVitaminA |
| Vitamin C | Vitamin C intake | HealthDataType.dietaryVitaminC (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.vitaminC) | HKQuantityTypeIdentifier.dietaryVitaminC |
| Vitamin D | Vitamin D intake | HealthDataType.dietaryVitaminD (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.vitaminD) | HKQuantityTypeIdentifier.dietaryVitaminD |
| Vitamin E | Vitamin E intake | HealthDataType.dietaryVitaminE (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.vitaminE) | HKQuantityTypeIdentifier.dietaryVitaminE |
| Vitamin K | Vitamin K intake | HealthDataType.dietaryVitaminK (iOS HealthKit Only) |
Sum | NutritionRecord (NutritionRecord.vitaminK) | HKQuantityTypeIdentifier.dietaryVitaminK |
๐ง Wellness
| Data Type | Description | Data Type | Supported Aggregation | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|
| Mindfulness Session | Meditation and mindfulness sessions | HealthDataType.mindfulnessSession |
Sum | MindfulnessSessionRecord | HKCategoryTypeIdentifier.mindfulSession |
๐ชท Cycle Tracking
| Data Type | Description | Data Type | Supported Aggregation | Android Health Connect API | iOS HealthKit API |
|---|---|---|---|---|---|
| Cervical Mucus | Cervical mucus observations for fertility | HealthDataType.cervicalMucus |
- | CervicalMucusRecord | HKCategoryTypeIdentifier.cervicalMucusQuality |
| Basal Body Temperature | Basal body temperature | HealthDataType.basalBodyTemperature |
Avg, Min, Max | BasalBodyTemperatureRecord | HKQuantityTypeIdentifier.basalBodyTemperature |
| Menstruation Flow | Menstrual flow intensity | HealthDataType.menstrualFlow |
- | MenstruationFlowRecord | HKCategoryTypeIdentifier.menstrualFlow |
| Ovulation Test | Ovulation test result | HealthDataType.ovulationTest |
- | OvulationTestRecord | HKCategoryTypeIdentifier.ovulationTestResult |
| Intermenstrual Bleeding | Intermenstrual bleeding spotting | HealthDataType.intermenstrualBleeding |
- | - | HKCategoryTypeIdentifier.persistentIntermenstrualBleeding |
๐ Migration Guides #
- Migration Guide from
v1.x.xtov2.0.0 - Migration Guide from
v2.x.xtov3.0.0
๐ค 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.