# Health data sync

Canonical page: https://docs.ovok.com/flutter-sdk/health-sync

`AppleHealthSync` and `AndroidHealthSync` read step counts and heart rate through
the [`health` package](https://pub.dev/packages/health/versions/13.1.4) and save
them as Ovok Observations. Step counts use daily totals. Heart rate uses a daily
average with minimum and maximum components. The first sync reads up to 30 days;
later daily syncs reread the last seven days so late samples can update saved
totals.

HealthKit does not reveal whether an app has read access for a data type. On
iOS, a permission check can therefore report an unknown status; an empty sync
may be the only indication that no records were shared.

## Configure the import [#configure-the-import]

Request permission through `HealthImportController` before mounting the sync
widget. The adapter asks for read access to the selected types.

```dart
final healthTypes = <HealthSyncSourceType>[
  HealthSyncSourceType.steps,
  HealthSyncSourceType.heartRate,
];

final healthImport = HealthImportController<HealthSyncSourceType>(
  types: healthTypes,
  adapter: HealthPluginImportAdapter(),
);

await healthImport.setEnabled(true);
```

Check `healthImport.enabled` after the request before showing the sync widget.

Create one configuration for the requested readings:

```dart
final healthConfiguration = HealthSyncConfiguration<HealthSyncSourceType>(
  dataToSync: {
    'stepCount': HealthSyncTypeConfiguration(
      typeIdentifiers: const [
        HealthSyncTypeIdentifier(typeIdentifier: HealthSyncSourceType.steps),
      ],
    ),
    'heartRate': HealthSyncTypeConfiguration(
      typeIdentifiers: const [
        HealthSyncTypeIdentifier(
          typeIdentifier: HealthSyncSourceType.heartRate,
        ),
      ],
    ),
  },
);
```

Mount the matching widget for the running platform:

```dart
AppleHealthSync(client: ovok, configuration: healthConfiguration)
```

```dart
AndroidHealthSync(client: ovok, configuration: healthConfiguration)
```

The widget starts a sync when mounted and restarts when its client or
configuration changes. It reports progress by health sync key. `wifiOnly`
pauses reads and saves until Wi-Fi is available; the default allows any
connected network. Set `minDate` on a type configuration to limit its earliest
read date. Health Connect limits historical reads to the access it grants; an
earlier `minDate` does not request additional history permission.

## Configure the host app [#configure-the-host-app]

On iOS, set the HealthKit share and update usage descriptions in `Info.plist`,
enable the HealthKit capability for the Runner target, and use iOS 14 or newer.

```xml
<key>NSHealthShareUsageDescription</key>
<string>Read step count and heart rate to sync health measurements.</string>
<key>NSHealthUpdateUsageDescription</key>
<string>Health data is read-only in this app.</string>
```

On Android, declare Health Connect's package query and the requested read
permissions in `AndroidManifest.xml`. Step count also requires activity
recognition permission.

```xml
<queries>
  <package android:name="com.google.android.apps.healthdata" />
  <intent>
    <action android:name="androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE" />
  </intent>
</queries>

<uses-permission android:name="android.permission.health.READ_STEPS" />
<uses-permission android:name="android.permission.health.READ_HEART_RATE" />
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
```

If the controller requests background access, also declare
`android.permission.health.READ_HEALTH_DATA_IN_BACKGROUND`. Health Connect
requires its privacy rationale activity setup and must be installed on the
device. See the [`health` package Android setup](https://pub.dev/packages/health/versions/13.1.4#google-health-connect-android)
for the rationale activity and app-review requirements.
