Skip to Content
HardwareTransportiOS (Native)

iOS: Connect via Bluetooth

Run @onekeyfe/hd-common-connect-sdk in WKWebView and bridge its low-level transport to CoreBluetooth. Start with the native iOS example  and Low-Level Transport Plugin contract.

The native host owns the Bluetooth lifecycle. The SDK owns protocol detection, framing and request/response processing.

Configure the app

  • Include NSBluetoothAlwaysUsageDescription with an explanation of hardware-wallet connectivity. Check additional requirements if you support older iOS versions.
  • Use CoreBluetooth and the bridge dependency declared by the native example.
  • Test on a physical iOS device with Bluetooth permission granted. Handle denied, restricted and powered-off states before scanning.

Build and load the JavaScript bundle

From the hardware-js-sdk checkout:

cd packages/connect-examples/native-ios-example/web yarn yarn build

Add the complete web_dist/ directory to the app target’s resources. Preserve relative asset paths. Create WKWebView and the bridge, register native handlers, then load the bundled HTML. Do not navigate a device-enabled WebView to untrusted content.

Use the example’s complete implementation and dependency versions. The tables below define what a custom bridge must guarantee.

Connection lifecycle

CBCentralManager.connect() starts a connection attempt. Do not resolve the JS connect request at that point.

StageRequired handling
ScanWait for .poweredOn; filter by the OneKey service, deduplicate results and stop scanning at a bounded deadline.
SelectMatch the selected peripheral UUID. If scanning to reconnect, connect only to that selected peripheral.
ConnectWait for didConnect; return failure on didFailToConnect or timeout.
DiscoverFind the required service and write/notify characteristics; handle discovery errors and missing characteristics.
SubscribeEnable notifications, then wait for didUpdateNotificationStateFor with no error and notifications enabled.
ReadyOnly now resolve the pending JS connection request. Complete each bridge callback once.

See Apple’s notification-state callback  for subscription completion.

PurposeUUID
Service00000001-0000-1000-8000-00805f9b34fb
Write00000002-0000-1000-8000-00805f9b34fb
Notify00000003-0000-1000-8000-00805f9b34fb

Ordered I/O

  • send receives hex prepared by the SDK. Reject malformed or odd-length hex; do not silently drop invalid bytes.
  • Honor the requested write mode and the peripheral’s write capacity. For writes without response, respect CoreBluetooth backpressure; a queued write is not proof that the device completed an SDK request.
  • Queue raw notification chunks per peripheral and return one unchanged hex chunk from each receive(uuid) call. Do not parse V1 headers or pad chunks to USB’s packet size.
  • On disconnect, reject pending work and clear the old connection’s queued notifications. A reconnect must not receive stale data from the previous connection.
  • Expose getProtocolV2PacketCapacity using the native write capacity. See the plugin interface.

SDK and wallet identity

Initialize the SDK with env: 'lowlevel' and your bridge plugin. Check initialization success. Use searchDevices() to select connectId, then getDeviceState(connectId) to read identity.deviceId.

The iOS peripheral UUID routes the connection; it is not the seed identity. Re-read state after reconnect, and stop if the expected wallet changed. See Identifiers.

PIN, passphrase and confirmation

Wire UI events before protected calls. Native prompts may collect input or show instructions, but the JS handler must preserve the original request’s response correlation.

Respond only to input requests. REQUEST_BUTTON, REQUEST_PASSPHRASE_ON_DEVICE, and device-only PIN events are notifications. A host callback returning “OK” does not approve the operation on the device. If the user cancels, cancel the selected SDK call and invalidate pending UI callbacks.

Use the same explicit standard/hidden-wallet binding for address confirmation and signing. Keep host-entered PIN/passphrase values out of logs and persistent storage.

Verify and recover

Test permission denial, Bluetooth powered off, missing characteristics, failed notification subscription, device input, cancellation and reconnect. Confirm an address on the physical device before considering the bridge functional.

Do not replay signing or firmware updates automatically after a timeout. Follow Disconnects and reconnection.

Last updated on