Skip to main content

Overview

The Synheart Wear Flutter SDK provides a unified API for streaming biometric data from Apple Health, Health Connect, WHOOP, Garmin, Fitbit, Oura and BLE heart-rate straps in Flutter applications. Key Features:
  • Cross-platform support (iOS + Android)
  • Real-time HR and HRV streaming
  • Unified data schema across all devices
  • Optional encrypted local cache (AES-256-GCM, key in the Keychain / Android secure storage)
  • Consent-based permissions

Installation

Add to your pubspec.yaml:
Install dependencies:
Requirements: Flutter 3.32+ (Dart 3.8+), iOS 16.0+, Android minSdk 28.

Platform Configuration

iOS Configuration

Add to ios/Runner/Info.plist:
Since 0.6.1 the SDK only reads health data, so NSHealthUpdateUsageDescription is not needed.

Android Configuration

Add to android/app/src/main/AndroidManifest.xml. The Flutter plugin’s own manifest declares no health permissions, so your app must declare every type it reads; a type that isn’t declared can’t be granted, and its reads come back empty. (The Kotlin SDK is different: its manifest declares them for you.)
Important: Your MainActivity must extend FlutterFragmentActivity (not FlutterActivity) for Android 14+.

Basic Usage

Recommended Pattern (Explicit Permission Control):
Alternative Pattern (Simplified): If you don’t need to control when the permission prompt appears, let initialize() request permissions itself:
Note: initialize() validates that wearable data is available and not stale (>24 hours old). If no data is available or data is too old, it will throw a SynheartWearError with codes NO_WEARABLE_DATA or STALE_DATA.

Sleep and overnight history

HealthAdapter reads finished nights and their overnight physiology from HealthKit or Health Connect. Results are keyed by the local day each night ended on (midnight of the wake day).
  • Pass sleepNights to fetchOvernightPhysiology. Without it, HRV and HR spread come from the whole day, and overnightHrBpm stays null.
  • HRV is SDNN on iOS (hrvSdnnMs) and RMSSD on Android (hrvRmssdMs); the other field is null.
  • A night crossing midnight stays whole; when a day has more than one sleep (a nap), the longest is kept.
  • Days with no record are absent from the map, never zero.
  • On Android, reads are throttled to one per 10 seconds to stay under Health Connect’s quota; a throttled call returns an empty map. Pass bypassThrottle: true for a user-initiated refresh.
  • Android reads reach about 30 days unless the app holds the history permission. Request it with HealthAdapter.requestHistoryAuthorization(); see Reading past 30 days.

Reading past 30 days (Android)

Health Connect lets an app read only the 30 days before it was first granted access, for every record type, unless it also holds READ_HEALTH_DATA_HISTORY. Declare it in the manifest (see Android Configuration), then ask for it; it is its own prompt:
isHistoryAvailable() is false where the device’s Health Connect doesn’t offer the permission; those devices stay at 30 days. On iOS there is no such limit: the checks report authorized and make no platform call. fetchActiveMinutes needs PermissionType.exercise, and on Android the READ_EXERCISE permission. To push this history into the personal baselines, see Health backfill.

Real-Time Streaming

Complete Example

Data Schema

Access metrics using the WearMetrics object:

Error Handling

Common Error Codes:
  • NO_WEARABLE_DATA: No health data available from connected devices
  • STALE_DATA: Latest data is older than 24 hours
  • PERMISSION_DENIED: User denied required permissions (thrown as PermissionDeniedError)
requestPermissions() accepts a reason: argument, but the SDK doesn’t show it anywhere; explain the request in your own UI before calling it.

BLE Heart Rate Monitor

Connect directly to any standard Bluetooth LE heart rate monitor (WHOOP Broadcast, Polar, Wahoo, Garmin HRM straps) for real-time HR streaming. No cloud backend needed.

Platform Setup

Android — Add to AndroidManifest.xml:
On Android, request BLUETOOTH_SCAN and BLUETOOTH_CONNECT at runtime yourself (for example with permission_handler). BleHrmProvider.requestPermission() is iOS-only; on Android it throws MissingPluginException. iOS — Add to Info.plist:

Usage

Polar H10 straps can also stream their accelerometer: pass enableMotion: true (and optionally motionSampleRateHz, default 50) to connect() and listen to bleHrm.onMotion. getBondedHrDevices() lists already-bonded straps without scanning.

HeartRateSample

Each sample from the stream contains:

Error Handling

BLE calls throw BleHrmError, whose code is a BleHrmErrorCode. Errors on the onHeartRate stream use the same type:

Notes

  • WHOOP devices require “Broadcast Heart Rate” enabled in the WHOOP app settings
  • RR intervals are available on some devices (e.g. Polar chest straps) but not all
  • Reconnection is automatic. Android retries 5 times, 3 s apart; iOS waits up to 30 s for CoreBluetooth to reconnect. After that disconnected is reported
  • Only one BLE HRM device can be connected at a time

Cloud Providers

WhoopProvider

GarminProvider (Cloud)

Full Garmin Connect integration via OAuth PKCE. Supports 12 summary types through the Garmin Health API backfill endpoint, plus activities (fetchActivities()): dailies, epochs, sleeps, stressDetails, hrv, userMetrics, bodyComps, pulseox, respiration, healthSnapshot, bloodPressures, and skinTemp.

GarminHealth (Native RTS)

The GarminHealth facade provides native Garmin device integration for scanning, pairing, and real-time streaming. All method signatures use generic SDK-owned types (ScannedDevice, PairedDevice, WearMetrics), never Garmin-specific types.
Important: The Garmin Health SDK Real-Time Streaming (RTS) capability requires a separate license from Garmin. This facade is available on demand for licensed integrations. The underlying Garmin Health SDK code is proprietary to Garmin and is not distributed as open source.

Platform-Specific Notes

Android

  • HRV: Health Connect reports RMSSD only, as hrv_rmssd; hrv_sdnn stays null
  • Distance: Uses DISTANCE_DELTA type
  • readMetrics() calls are spaced at least 10 seconds apart to stay under Health Connect’s read quota. A call for the same data inside that gap gets the previous result; any other call waits out the gap, then reads.
  • Requires Health Connect app installed
  • MainActivity must extend FlutterFragmentActivity

iOS

  • Requires iOS 16+ and the HealthKit capability enabled in Xcode
  • HRV: HealthKit reports SDNN only, as hrv_sdnn; hrv_rmssd stays null
  • No HealthKit background delivery: reads happen when your app calls the SDK
  • Real-time reads look back 2 minutes and run at most every 10 s; calls in between return no new data

API Reference

SynheartWear

Main SDK class for interacting with wearable devices. Constructor:
Methods:

SynheartWearConfig

Configuration for the SDK. Constructor:

WearMetrics

Biometric data container. Methods: Properties:

HealthAdapter

Static reads from HealthKit / Health Connect. See Sleep and overnight history.

Resources