Skip to main content

Bluetooth

Use the Bluetooth module to discover supported BLE devices, connect to them, and receive normalized measurements. Your app owns the Bluetooth manager lifetime, the accepted device list, the user experience around measurement, and what happens to each result.

Before you start​

1. Create a long-lived BLE manager​

Create one BleManager for the app or Bluetooth feature. Keep it outside a component render, or in a stable app-level ref, so a render does not replace the native manager.

import { BleManager } from "react-native-ble-plx";
import {
BTProvider,
IntegratedDevices,
} from "@ovok/native/bt-management";

const bleManager = new BleManager();
const acceptedDevices = [
IntegratedDevices.BP2,
IntegratedDevices.F4,
] as const;

acceptedDevices is a typed allowlist. The SDK only creates handlers for entries in that list. Keep the array identity stable for the lifetime of the provider.

2. Mount BTProvider around the measurement flow​

BTProvider requests Bluetooth access, creates the managed device runtime, starts discovery, and tears it down when it unmounts. Keep it mounted for as long as the flow should own the scan and connections.

export function MeasurementFlow() {
return (
<BTProvider
bleManager={bleManager}
acceptedDevices={acceptedDevices}
onDeviceFound={(device) => device.connect()}
onDeviceStatusChanged={({ deviceData, status }) => {
console.log(deviceData.name, status);
}}
onResult={(result) => {
const idempotencyKey = result.id;
const measurement = result.data;

void saveMeasurement({ idempotencyKey, measurement });
}}
onError={({ deviceData, error, code }) => {
reportBluetoothError(deviceData?.name, error, code);
}}
>
<MeasurementScreen />
</BTProvider>
);
}

The permission request runs when the provider mounts and is checked again when the app returns to the foreground. If access is denied, the provider renders its default settings prompt; supply permissionFallback to render your own.

3. Handle readings and connection state​

A result contains deviceData and normalized measurement data. It also has a stable id for deduplication. The SDK defines id as an enumerable property that is non-writable at runtime, so object spreads and JSON serialization include it. Pass it as an idempotency key when the app may retry uploads.

Use onDeviceStatusChanged for the compact status values: Connected, Disconnected, Measuring, and LowBattery. Use onConnectionEvent for pairing prompts, bonding, battery values, and history transfer progress. A transfer's progress.total can be missing; show a count rather than a percentage unless a total is present.

The provider callbacks are app-owned boundaries. Persist, associate with a patient, validate, and upload measurements in your app. The SDK does not choose a patient or submit results to your backend.

4. Add a device selection and pairing experience​

For apps that connect to whichever accepted device is nearby, enable autoConnect. One discovered device connects automatically after the settle delay; when multiple devices are found, handle onDeviceSelectionRequired and present a chooser such as BluetoothDevicePicker.

For a discover-and-pair screen, use PairingFlow. It reads nearby devices from the provider runtime and stores remembered device IDs through the storage adapter you supply. See Bluetooth state notice to give users a clear route to enable Bluetooth or permissions.

5. Add device UI where it helps​

The package has two device catalog approaches:

Catalog entries are metadata. Check each entry's acceptedDevices before offering a connect action; entries with no accepted device declaration cannot be passed to BTProvider.

For ECG readings, prepare the waveform samples and sampling rate from the result data in your app, then render them with EcgStripViewer. The viewer presents a trace; it does not parse a device result or interpret a rhythm.

Lifecycle and operational choices​

  • Mount one provider for one active scanning scope. Unmounting it stops scanning, detaches subscriptions, and destroys its managed BTManager.
  • Use useScanControl to pause and resume scanning without unmounting the provider.
  • Configure background delivery separately. It requires durable storage and native background configuration; it is opt-in.
  • Tune result filtering only when the product requires it. resultPolicies can select all, daily-totals-only, or first-reading-per-kind-per-connection at the device or measurement level.
  • Keep native permission and Bluetooth-on state distinct. Permission being granted does not guarantee that the radio is powered on.