Advanced Bluetooth usage
Manage a Bluetooth session directly, tune runtime hooks, and use deterministic BLE fixtures.
- Stable unknown
- Release candidate since 1.16.1-rc.3
- Development since 1.16.1-dev.2111+9796905
Most apps should use BTProvider. Use BTManager directly only when the app needs to own permission handling, runtime context, scanning, and cleanup itself.
Manage a session directly
BTManager takes the app-owned BleManager, a stable accepted-device tuple, and optional manager options. The direct manager API does not request platform permissions or provide the React runtime hooks.
import { BleManager } from "react-native-ble-plx";
import {
BTManager,
IntegratedDevices,
} from "@ovok/native/bt-management";
const bleManager = new BleManager();
const acceptedDevices = [IntegratedDevices.BP2] as const;
const manager = new BTManager(bleManager, acceptedDevices, {
autoConnect: true,
autoConnectDelayMs: 700,
oneReadingPerConnection: true,
});
manager.onDeviceFound(async (device) => {
await device.connect();
});
manager.onResult((result) => {
saveMeasurement(result.id, result.data);
});
manager.onError((failure) => reportBleError(failure));
manager.startScan();
// In the owning effect or service teardown:
manager.destroy();Register handlers before starting discovery. The manager exposes callbacks for discovery, status, connection events, results, and errors. Its lifecycle controls include startScan, pauseScan, resumeScan, setBackgroundScanEnabled, restoreDevices, keepConnecting, forget, stopScan, and destroy.
Use pauseScan and resumeScan for a temporary discovery pause; they preserve managed devices and callback registrations. stopScan removes callbacks, disconnects managed devices, and clears the device set. destroy additionally marks the manager unusable. Do not start or stop discovery directly through BleManager while the SDK manager owns the scan.
What a connection does before the first command
Once a device is connected and its services are discovered, the SDK reads Device Information and the battery level, then subscribes to every declared characteristic. The first command is written only after the device reports notifications or indications as enabled on each of them, so a device that answers a control-point write with nothing until indications are on receives its command in the right order. Where the platform cannot read that setting, the SDK waits a short fixed time instead.
When a read, a subscription or the first command fails because the device needs pairing, the SDK keeps the link, emits a pairing connection event with pairingCodeRequired set, and tries the step again while the user finishes the system pairing dialog, for up to 30 seconds. If the link drops or the time runs out, the step is abandoned and the connection carries on without it.
A declared device that has no clock protocol of its own (clockSync is unknown, as for the Bluetooth SIG profiles) and exposes a writable Current Time characteristic (service 0x1805, characteristic 0x2A2B) gets the phone's time written on connect, with a clock-synchronized connection event. This follows BTProvider's clockSync option: enabled: false leaves the device clock alone, timezone picks the local or UTC time, and now supplies the time. A device whose clock cannot be written keeps its own time.
React runtime hooks
The runtime hooks below require BTProvider, except for the two state and permission hooks.
| Hook | Behavior |
|---|---|
useNearbyDevices() | Returns discovered runtime devices and pair(id), which connects the matching device. |
usePairedDevices({ storage, storageKey?, autoPair? }) | Stores remembered peripheral IDs with app-provided async storage. With autoPair, connects a remembered device when it is discovered. |
useDeviceConnection(id) | Returns the current status and the most recent connection events for that device. |
useMeasurements(onResult?, options?) | Collects a bounded in-memory list of results, deduplicated by stable result ID. |
useScanControl() | Exposes pause and resume controls for the provider's manager. |
useRuntimeEvent(event, callback) | Subscribes to a runtime event; earlier events are not replayed. |
useBluetoothState({ bleManager?, requestPermission? }) | Observes radio state and exposes a permission request function. |
useRequestPermissions({ onAccessPermissionChanged? }) | Requests platform Bluetooth permission and returns the current access result. |
useMeasurements supports all, first-reading-per-kind-per-connection, and daily-totals-only. The first-reading policy resets when the runtime receives a bond event. Daily totals are deduplicated by measurement type and UTC calendar day using the measurement's end, start, or recorded-at time. The list defaults to the latest 100 accepted results; call clear() to reset its local state.
useBackgroundSync exposes a UI setting with on, off, restricted, and blocked states. It toggles the manager's background-scan flag and calls the optional app callback. It does not persist the preference or replace the durable queue configured through BTProvider.backgroundSync. Keep the provider prop and the UI setting connected to the same app state.
useHealthImport is an adapter-driven health-store hook, not a BLE permission helper. Its adapter reports authorization per type and requests the selected set. Keep its types array and adapter identity stable so configuration changes do not trigger repeated refreshes.
Compose the runtime manually
createBluetoothRuntime and BluetoothRuntimeProvider are exported for advanced composition. The runtime provider supplies context only; it does not create a manager, request permissions, scan, forward events, or clean up devices. See BluetoothRuntimeProvider and prefer the provider's callbacks for ordinary app integration.
Runtime events are deviceFound, pairedDevices, error, status, result, and connection. Hooks subscribe from the time they mount and do not replay earlier events.
Deterministic BLE fixtures
The @ovok/native/bt-management testing exports include createFakeBleManager and createFakeBleDevice. The fake manager can emit discovery and radio-state changes. A fake device supports connection, characteristic reads and notifications, notification-state (Client Characteristic Configuration) reads, MTU requests, and disconnects. These helpers do not simulate operating-system permissions or real platform background execution.
defineRecordedDeviceFrames groups app-owned recorded frames by device key. replayRecordedFrames sends each frame to an app-provided sink in order and can apply a delay per frame. Use these helpers to exercise parsing and result-handling code without live hardware.
See the Bluetooth guide, BTProvider reference, and runtime hooks.
Last updated on