PairingFlow
PairingFlow renders devices discovered by the active Bluetooth runtime, starts
pairing, presents a pairing-code field when the runtime requests one, and remembers
the ID of a device after it becomes bonded. Import it from @ovok/native/ui and
render it beneath BTProvider.
import { BTProvider } from "@ovok/native/bt-management";
import { PairingFlow } from "@ovok/native/ui";
<BTProvider bleManager={bleManager} acceptedDevices={acceptedDevices}>
<PairingFlow
storage={pairedDeviceStorage}
onPairingCode={(code, device) => confirmPairingCode(device, code)}
onPaired={(device) => navigation.navigate("DeviceDetails", { id: device.id })}
onError={(error, device) => reportPairingError(error, device?.id)}
/>
</BTProvider>
BTProvider owns discovery and the BLE runtime. This component does not create a
manager or start a scan. Supply a PairedDeviceStorage implementation; the flow
stores a JSON array of IDs, not device objects or credentials.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
storage | PairedDeviceStorage | Required | Async getItem and setItem adapter for remembered IDs. |
storageKey | string | @ovok/native/paired-devices | Storage key shared with the paired-device hook. |
getDeviceImage | (device: RuntimeDevice) => string | undefined | — | Return an image URI for a discovered device. |
onPaired | (device: RuntimeDevice) => void | — | Called after a bonded device has been remembered. |
onPairingCode | (code: string, device: RuntimeDevice) => Promise<void> | void | — | Handle a code when pairing requires app/device-specific confirmation. |
onError | (error: Error, device?: RuntimeDevice) => void | — | Observe pair or code-handler errors. |
renderHeader | (state: PairingFlowRenderState) => ReactNode | Default heading | Replace the heading and description. |
renderEmpty | (state: PairingFlowRenderState) => ReactNode | Default empty message | Replace the no-devices content. |
renderDevice | (device, actions) => ReactNode | Default pair row | Replace each row; actions provide pair, forget, and the flow status. |
labels | Record<string, string> | English copy | Override built-in labels. |
theme, slots | OvokUiProps | Active Paper theme and SDK slots | Apply shared UI theme or replace Paper primitives. |
testID | string | — | Set the flow container ID; the code input appends -code. |
The storage contract is:
interface PairedDeviceStorage {
getItem(key: string): Promise<string | null>;
setItem(key: string, value: string): Promise<void>;
}
getItem should return the JSON array previously written by the flow, or null if
the key is empty. The SDK validates parsed values as string IDs and treats invalid
JSON as an empty list.
Pairing lifecycle
The flow exposes these statuses through render state and custom device actions:
| Status | Meaning |
|---|---|
idle | No pairing attempt is active. |
pairing | useNearbyDevices().pair is in progress or awaiting the bond event. |
code-required | A runtime pairing event requested a code; the flow shows its input. |
paired | The selected device emitted a bonded event. |
error | Pairing or code handling failed. |
onPairingCode receives the trimmed value and selected runtime device. The flow
does not confirm the code itself; provide a handler for the device's pairing
procedure. A resolved handler returns the status to pairing. The matching bonded
event updates the visible status to paired; after the underlying pair operation
resolves, the flow stores the ID and calls onPaired only if it observed that event.
If the pair operation rejects, the flow reports an error and does not store the ID.
The default row starts pairing and shows optional device image, name, manufacturer,
and pair action. It does not render a forget control. To offer forgetting, supply
renderDevice and call actions.forget() from your row. That method asks the active
Bluetooth manager to forget the device, then removes its ID from storage; it rejects
if the manager is not ready.
PairingFlowRenderState contains devices, paired IDs, optional selected
device, status, and optional error. renderHeader and renderEmpty receive this
state. renderDevice receives one device and an actions object:
{
pair: () => Promise<void>;
forget: () => Promise<void>;
status: PairingFlowStatus;
}
The status is shared by the flow's current selection. If rows need independent per-device state or richer accessibility behavior, own that presentation in the custom row.
The labels keys and default copy are:
| Key | Default |
|---|---|
header | Add a device |
description | Wake your monitor and choose it when it appears nearby. |
empty | No supported devices found yet. |
device | Bluetooth device (used when the manufacturer name is empty) |
pair | Pair |
pairingCodePrompt | Type the code your monitor shows |
pairingCode | Pairing code |
continue | Continue |
pairing | Pairing the selected device… |
paired | The selected device is ready. |
retry | Try again |
remembered | A count-specific remembered-device message |
The default pairing, paired, and remembered messages include the selected device
name or count. A value supplied in labels replaces the message verbatim; the flow
does not interpolate placeholders in custom strings.
See Reusable flows for integration guidance and Bluetooth for provider and device discovery setup.