On this page
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
NSBluetoothAlwaysUsageDescriptionwith 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 buildAdd 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.
| Stage | Required handling |
|---|---|
| Scan | Wait for .poweredOn; filter by the OneKey service, deduplicate results and stop scanning at a bounded deadline. |
| Select | Match the selected peripheral UUID. If scanning to reconnect, connect only to that selected peripheral. |
| Connect | Wait for didConnect; return failure on didFailToConnect or timeout. |
| Discover | Find the required service and write/notify characteristics; handle discovery errors and missing characteristics. |
| Subscribe | Enable notifications, then wait for didUpdateNotificationStateFor with no error and notifications enabled. |
| Ready | Only now resolve the pending JS connection request. Complete each bridge callback once. |
See Apple’s notification-state callback for subscription completion.
| Purpose | UUID |
|---|---|
| Service | 00000001-0000-1000-8000-00805f9b34fb |
| Write | 00000002-0000-1000-8000-00805f9b34fb |
| Notify | 00000003-0000-1000-8000-00805f9b34fb |
Ordered I/O
sendreceives 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
getProtocolV2PacketCapacityusing 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.