Skip to main content

Overview

The Synheart Wear Swift SDK provides native iOS support for streaming biometric data from Apple Watch via HealthKit, vendor cloud APIs (WHOOP, Garmin, Fitbit, Oura), direct BLE heart-rate sensors, and offline Apple Health export.xml backfill.

Installation

Swift Package Manager

Add to your Package.swift:
dependencies: [
    .package(url: "https://github.com/synheart-ai/synheart-wear-swift.git", from: "0.4.0")
]
Or in Xcode:
  1. File → Add Packages…
  2. Enter: https://github.com/synheart-ai/synheart-wear-swift.git

Requirements

  • iOS 13.0+
  • Swift 5.9+
  • Xcode 15.0+

Quick Start

Configure HealthKit

Add to Info.plist:
<key>NSHealthShareUsageDescription</key>
<string>We need access to your health data</string>
Enable HealthKit capability in Xcode:
  • Target → Signing & Capabilities → + Capability → HealthKit

Initialize SDK

import SynheartWear

let config = SynheartWearConfig(
    enabledAdapters: [.platformHealth],
    enableLocalCaching: true
)

let synheartWear = SynheartWear(config: config)

Request Permissions & Read Data

Task {
    let permissions: Set<PermissionType> = [
        .heartRate,
        .steps,
        .calories
    ]

    let result = try await synheartWear.requestPermissions(permissions: permissions)

    if result[.heartRate] == true {
        try await synheartWear.initialize()
        let metrics = try await synheartWear.readMetrics()
        print("Heart Rate: \(metrics.getMetric(.hr) ?? 0) bpm")
    }
}

Real-Time Streaming

streamHR(interval:) returns a Combine AnyPublisher<WearMetrics, Error>. Use streamHRAsync(interval:) if you prefer AsyncStream.
import Combine

var cancellables = Set<AnyCancellable>()

synheartWear.streamHR(interval: 5.0)
    .sink(
        receiveCompletion: { _ in },
        receiveValue: { metrics in
            if let hr = metrics.getMetric(.hr) {
                print("Current HR: \(hr) bpm")
            }
        }
    )
    .store(in: &cancellables)

// Async/await alternative:
Task {
    for await metrics in synheartWear.streamHRAsync(interval: 5.0) {
        if let hr = metrics.getMetric(.hr) {
            print("Current HR: \(hr) bpm")
        }
    }
}

BLE Heart Rate Monitor

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

Setup

Add to Info.plist:
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app uses Bluetooth to connect to heart rate monitors.</string>

Usage

import SynheartWear

let config = SynheartWearConfig(enabledAdapters: [.bleHrm])
let synheartWear = SynheartWear(config: config)

// Access the BLE HRM provider
guard let bleHrm = synheartWear.bleHrm else { return }

// Scan for nearby HR monitors
let devices = try await bleHrm.scan(timeoutMs: 10000, namePrefix: "WHOOP")

// Connect to a device
try await bleHrm.connect(deviceId: devices.first.deviceId, sessionId: "my-session")

// Stream heart rate samples
for await sample in bleHrm.onHeartRate {
    print("BPM: \(sample.bpm)")
    if let rr = sample.rrIntervalsMs {
        print("RR: \(rr)")
    }
}

// Disconnect
try await bleHrm.disconnect()

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

Cloud providers (WHOOP / Garmin / Fitbit / Oura)

Each cloud vendor is exposed via a typed accessor on SynheartWear plus the generic getProvider() lookup:
let whoop:  WhoopProvider?  = synheartWear.whoop
let garmin: GarminProvider? = synheartWear.garmin
let fitbit: FitbitProvider? = synheartWear.fitbit
let oura:   OuraProvider?   = synheartWear.oura
OAuth is mediated by the Synheart Wear API; the device never sees vendor access tokens. Call provider.connect() to launch the system browser at the authorize URL, then provider.connectWithCode(code:state:redirectUri:) from your deep-link handler. For Fitbit and Oura, the cloud delivers a vendor_user_id directly via deep link — pass that as the code argument.

Apple Health XML Backfill

The AppleXmlImport module ingests an Apple Health export.xml (the file produced by the Health app’s “Export All Health Data” feature) and converts it into a stream of AppleHealthSample records. The streaming SAX parser stays under a 200 MB working-set budget regardless of file size, so multi-hundred-MB exports are safe.
import SynheartWear

let xmlURL: URL = ...   // path to unzipped export.xml

let importer = AppleHealthXmlImport()
let result = try await importer.import(
    fileURL: xmlURL,
    sink: MyIngestSink()  // conforms to AppleXmlIngestSink
)
print("imported \(result.totalSamples) samples")
Each sample’s stable identity is computed by IdempotencyKey (SHA-256 over a canonical subset of fields), so re-running the import on the same file produces the same keys and downstream sinks can dedupe safely.

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. 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.
import SynheartWear

let garmin = GarminHealth(licenseKey: "your-garmin-sdk-key")
try await garmin.initialize()

// Scan for devices
for await devices in garmin.scannedDevicesStream() {
    print("Found \(devices.count) devices")
}

// Pair and read metrics
let paired = try await garmin.pairDevice(scannedDevice)
let metrics = try await garmin.readMetrics()
For cloud-based Garmin data (OAuth + webhooks), use GarminProvider instead.

Resources

For comprehensive documentation, see the full README on GitHub.