BTProvider
BTProvider is the React entry point for BLE device integration. The app owns the
BleManager instance and the persistence or upload policy; the provider owns the
scan lifecycle while it is mounted and exposes typed callbacks for discovery,
connection, errors, status, and readings.
Minimal integration
import { BleManager } from "react-native-ble-plx";
import { BTProvider, IntegratedDevices } from "@ovok/native/bt-management";
const bleManager = new BleManager();
const acceptedDevices = [IntegratedDevices.BP2] as const;
export function BluetoothRoot({ children }: { children: React.ReactNode }) {
return (
<BTProvider
bleManager={bleManager}
acceptedDevices={acceptedDevices}
onDeviceFound={(device) => device.connect()}
onResult={({ id, deviceData, data }) => {
saveMeasurement({ id, deviceData, data });
}}
>
{children}
</BTProvider>
);
}
Create the manager once and keep the same instance for the app flow. BTProvider
starts discovery after permission is available and destroys its BTManager when it
unmounts. It does not use React Navigation or useFocusEffect; if a screen needs
to pause discovery, use the manager from the runtime or mount the provider at the
appropriate app boundary.
Props
| Prop | Type | Description |
|---|---|---|
bleManager | BleManager | Host-owned react-native-ble-plx manager. |
acceptedDevices | readonly AcceptedDevice[] | Built-in IntegratedDevices values and/or validated defineCustomDevice declarations. |
onDeviceFound | (device, manager) => Promise<void> | Called for a matching peripheral. Call device.connect() when the app wants to connect. |
onResult | (result) => void | Receives { id, deviceData, data }. id is stable for the same recorded reading. |
onError | (error) => void | Receives { error, code?, deviceData? }. error is `BluetoothError |
onDeviceStatusChanged | (change) => void | Receives the device, one of the four DeviceStatus values, and an optional measurement type. |
onConnectionEvent | (event) => void | Receives connection/disconnection events with the device data. |
oneReadingPerConnection | boolean | Stops a streaming device after its first delivered reading for that connection. |
deliveredEcgFileNames | readonly string[] | Names of Viatom/compatible ECG files already delivered by the app. |
autoConnect | boolean | Connects a discovered device automatically after the settle window. |
autoConnectDelayMs | number | Delay used by automatic connection before selecting a candidate. |
onDeviceSelectionRequired | ({ devices, select }) => void | Receives multiple candidates when automatic connection needs an app selection UI. |
resultPolicies | Partial<Record<string, DeviceResultPolicy>> | Select all, daily-totals-only, or first-reading-per-kind-per-connection per device; use byMeasurement for per-measurement overrides. |
backgroundSync | BackgroundSyncOptions | Enables durable result delivery and platform restoration. See Background sync. |
permissionFallback | () => ReactNode | Optional replacement UI when permission gating is enabled and Bluetooth permission is unavailable. |
gateOnPermission | boolean | When true, renders permissionFallback (or the default fallback) instead of children until permission is granted. Defaults to false, so children remain mounted while permission is pending or refused. |
onAccessPermissionChanged | (granted: boolean) => void | Called when the permission state changes. |
children | ReactNode | The subtree that consumes the provider/runtime. |
onDeviceFound is optional. If the app does not connect a discovered device, the
SDK leaves it available to the runtime and does not invent a connection policy.
The callback is asynchronous so the app can await connect() and handle its own
errors.
When autoConnect is enabled, the manager connects the only candidate found in its
settle window. If several candidates are available, onDeviceSelectionRequired
receives devices and a select(device) function. The SDK does not choose between
the candidates for the app.
<BTProvider
bleManager={bleManager}
acceptedDevices={acceptedDevices}
autoConnect
autoConnectDelayMs={750}
onDeviceSelectionRequired={({ devices, select }) => {
setCandidates({ devices, select });
}}
>
{children}
</BTProvider>
Permission states
By default, children remain mounted while permission is pending or refused, and
the provider reports access changes through onAccessPermissionChanged. Set
gateOnPermission to true when Bluetooth-dependent children must not render
without permission. In that mode, the provider renders permissionFallback, or
the SDK's DefaultPermissionFallback when no replacement was supplied. A refused
device is not repeatedly re-emitted just because the scan continues. Use
onAccessPermissionChanged or useBluetoothState to offer a settings action.
Device statuses
The enum intentionally has only four values:
enum DeviceStatus {
CONNECTED = "Connected",
DISCONNECTED = "Disconnected",
MEASURING = "Measuring",
LOW_BATTERY = "LowBattery",
}
Connecting, Pairing, Ready, Syncing, Complete, Idle, and Error are
not SDK status values. If an app needs those labels, derive them from its own
connection state, callbacks, and error state.
measurementTypeKey may be present on MEASURING and on the following
CONNECTED notification when the device has finished that measurement.
Callback data
type ErrorCallback = {
error: BluetoothError | Error | string;
code?: BluetoothErrorCode;
deviceData?: DeviceData;
};
type DeviceData = {
id: string;
name: DeviceKey;
localName: string;
manufacturerData: string;
manufacturerName?: string;
model?: string;
sn: string;
measurementTypes: MeasurementTypeKey[];
};
The data object in onResult is an @ovok/core measurement shape selected by
the accepted device. The native layer does not add a patient, account, upload,
or storage field. Add those in the host application's adapter.
When backgroundSync is enabled, the callback result also includes queueId,
queuedAt, and attempt. id identifies the recorded reading and remains the
same when that reading is retried; queueId identifies one queue insertion and can
change when the same reading is enqueued again.
App lifecycle
The provider creates its manager in an effect, starts scanning after Bluetooth is
powered on, and cleans up the scan, subscriptions, devices, and callbacks on
unmount. Do not create a second provider with the same BleManager for the same
flow. For background restoration, create the manager with
createBackgroundBleManager and pass the same stable restoration identifier in
backgroundSync.
Related APIs
- Bluetooth integration for foreground/background flows.
- Custom devices for a device not shipped in the catalog.
- Advanced usage for the public manager controls and test kit.
- on-device-found, on-result, on-error, and on-device-status-changed for callback details.