Skip to main content

Overview

The Synheart Wear Kotlin SDK provides native Android support for reading biometric data from wearables via Health Connect, vendor cloud APIs (WHOOP, Garmin, Fitbit, Oura), and direct BLE heart-rate sensors.

Installation

Gradle (Kotlin DSL)

Published to Maven Central as ai.synheart:synheart-wear:

Requirements

  • Android minSdk 21, compileSdk 34, Java 17
  • The library is built with Kotlin 2.3 and depends on kotlin-stdlib 2.3.0, so your project needs a Kotlin compiler that can read 2.3 metadata
  • Health Connect installed on the device (built in on Android 14+, otherwise from the Play Store)

Quick Start

Create the SDK

Initialize, then ask for Health Connect access

Call initialize() first: every other call throws SynheartWearException (“SDK not initialized”) until it has run. requestPermissions() does not show the Health Connect permission screen. It reports which of the requested permissions are already granted. Show the screen yourself with Health Connect’s PermissionController contract, which needs an Activity:

Real-Time Streaming

streamHRV(windowMs = 5000L) emits HRV the same way.

Health Connect

Reads from any wearable companion app that syncs to Jetpack Health Connect — Fitbit, Garmin Connect, Samsung Health, Google Fit, Polar Flow, etc. (Apple Watch is not supported on Android — it only syncs to Apple Health on iOS.)

AndroidManifest.xml

The SDK’s own manifest declares 17 Health Connect read permissions plus READ_HEALTH_DATA_IN_BACKGROUND, and the <queries> block for the Health Connect app, so your app inherits them. (The Flutter plugin does not; Flutter apps declare their own.) That list includes types the SDK does not read today (oxygen saturation, respiratory rate, body temperature, weight, height, body fat, lean body mass, speed). If your app doesn’t use them, remove them so Play review doesn’t ask you to justify them:
READ_HEALTH_DATA_HISTORY is not in the inherited list. Declare it yourself to read more than 30 days back; see Health backfill. Play policy requires a permissions-rationale screen and a privacy-policy entry point. Add both to your own manifest:

Record types read

HealthConnectAdapter reads HeartRateRecord, HeartRateVariabilityRmssdRecord, StepsRecord, TotalCaloriesBurnedRecord, ActiveCaloriesBurnedRecord, DistanceRecord (reported in meters), ExerciseSessionRecord and SleepSessionRecord.

Sleep and overnight history

HealthConnectAdapter also implements HealthHistoryReader, which returns per-night summaries keyed by local date:
SleepNightSummary carries totalAsleepMinutes, deepMinutes and remMinutes. OvernightPhysiologySummary carries hrvRmssdMs and restingHrBpm.

Availability

Per-record retention is platform-controlled (typically ~30 days for HR, longer for sleep). For older data use a cloud provider.

Cloud providers (WHOOP / Garmin / Fitbit / Oura)

Cloud providers exist only when you pass a CloudConfig and list the vendor in enabledAdapters. They are created during initialize().
getProvider() throws SynheartWearException when the vendor isn’t enabled or cloudConfig is missing. isCloudAdapterEnabled(vendor) checks without throwing. OAuth is mediated by the Synheart Wear API; the device never sees vendor access tokens. Call provider.connect() to get an authorization URL, open it in a browser, then call provider.connectWithCode(code, state, redirectUri) from your deep-link handler. readMetricsFromProvider(...) reads a connected vendor’s data as WearMetrics. Full code sample in the SDK README’s Cloud Wearables section.

BLE Heart Rate Monitor

Connect directly to any standard Bluetooth LE heart rate monitor for real-time HR streaming.

Setup

Add to AndroidManifest.xml:
Request BLUETOOTH_SCAN and BLUETOOTH_CONNECT at runtime on Android 12+ before scanning.

Usage

bleHrm is null until initialize() has run.
Errors throw BleHrmException, whose errorCode is a BleHrmErrorCode: PERMISSION_DENIED, BLUETOOTH_OFF, DEVICE_NOT_FOUND, SUBSCRIBE_FAILED or DISCONNECTED. After an unexpected disconnect the provider retries three times (1 s, 2 s, 4 s) before giving up.

Supported Devices

Works with any BLE device implementing the standard Heart Rate Profile (0x180D):
  • WHOOP (Broadcast HR mode)
  • Polar H10, OH1
  • Wahoo TICKR
  • Garmin HRM-Pro / HRM-Dual

Garmin Health SDK (Native RTS)

The GarminHealth facade provides native Garmin device integration for scanning, pairing, and real-time streaming using generic SDK-owned types.
Important: The Garmin Health SDK Real-Time Streaming (RTS) capability requires a separate license from Garmin. The underlying Garmin Health SDK code is proprietary to Garmin and is not distributed as open source. In the Maven Central build, initialize() succeeds but every data call throws SynheartWearException; licensed integrations build with the Garmin overlay.
For cloud-based Garmin data (OAuth + webhooks), use the GARMIN cloud provider instead.

Local cache

SynheartWearConfig.enableLocalCaching (default true) keeps recent readings on the device; getCachedSessions(), getCacheStats() and clearOldCache() manage it, and purgeAllData() clears the cache and revokes consents.
enableEncryption is accepted but not applied in 0.4.2: the Kotlin cache is written unencrypted. Don’t rely on it for data that must be encrypted at rest.

Errors

SDK calls throw SynheartWearException(message, cause, code). BLE calls throw BleHrmException (see above).

Resources