本页目录
iOS:通过蓝牙连接(原生)
在 WKWebView 中运行 @onekeyfe/hd-common-connect-sdk,通过底层传输插件桥接到 CoreBluetooth。以原生 iOS 示例 和底层传输插件契约为起点。
原生宿主负责蓝牙生命周期;SDK 负责协议探测、帧处理和请求/响应处理。
应用配置
- 添加
NSBluetoothAlwaysUsageDescription,说明连接硬件钱包的用途。支持较旧 iOS 版本时,核对其额外要求。 - 使用 CoreBluetooth,以及原生示例声明的桥接依赖。
- 在授予蓝牙权限的真实 iOS 设备上测试。扫描前处理权限拒绝、受限和蓝牙关闭状态。
构建并加载 JavaScript 包
在 hardware-js-sdk 仓库中运行:
cd packages/connect-examples/native-ios-example/web
yarn
yarn build将完整的 web_dist/ 目录加入应用 target 的资源,保留相对资源路径。依次创建 WKWebView 和桥接、注册原生处理器,再加载打包的 HTML。不要让具有设备访问能力的 WebView 导航到不可信内容。
使用示例的完整实现及依赖版本。自定义桥接必须满足以下完成条件。
连接生命周期
CBCentralManager.connect() 只是发起连接尝试,不能在这时就将 JS connect 请求返回为成功。
| 阶段 | 必须处理的事项 |
|---|---|
| 扫描 | 等待 .poweredOn,按 OneKey 服务过滤、去重,并在设定的截止时间停止扫描。 |
| 选择 | 匹配用户所选外设 UUID;通过扫描恢复连接时也只能连接该外设。 |
| 连接 | 等待 didConnect;didFailToConnect 或超时均返回失败。 |
| 发现 | 查找所需服务、写入和通知特征,处理发现错误及缺失特征。 |
| 订阅 | 启用通知,等待 didUpdateNotificationStateFor 无错误且通知已启用。 |
| 就绪 | 此时才完成待处理的 JS 连接请求;每个桥接回调只完成一次。 |
通知订阅完成的依据见 Apple 的通知状态回调 。
| 用途 | UUID |
|---|---|
| 服务 | 00000001-0000-1000-8000-00805f9b34fb |
| 写入 | 00000002-0000-1000-8000-00805f9b34fb |
| 通知 | 00000003-0000-1000-8000-00805f9b34fb |
有序收发
send接收 SDK 准备的十六进制数据。格式错误或长度为奇数时返回失败,不要静默丢弃无效字节。- 遵守请求的写入模式和外设写入容量。无响应写入应遵守 CoreBluetooth 背压;写入入队不代表设备已经完成 SDK 请求。
- 按外设维护原始通知块队列。每次
receive(uuid)返回一个未修改的十六进制数据块,不解析 V1 头部,也不补齐到 USB 包长。 - 断连时拒绝待处理操作,清空旧连接的通知队列;重连后不得读到上一条连接的残留数据。
- 用原生写入容量实现
getProtocolV2PacketCapacity。参见插件接口。
SDK 与钱包身份
用 env: 'lowlevel' 和桥接插件初始化 SDK,并检查结果。通过 searchDevices() 选择 connectId,再调用 getDeviceState(connectId) 读取 identity.deviceId。
iOS 外设 UUID 用于连接路由,不是种子身份。重连后重新读取状态;如果目标钱包身份变化,应停止操作。参见标识符。
PIN、密码短语与确认
在受保护调用前接入 UI 事件。原生弹窗可以收集输入或显示提示,但 JS 处理器必须保留原请求的响应关联字段。
只回答输入请求。REQUEST_BUTTON、REQUEST_PASSPHRASE_ON_DEVICE 和设备端 PIN 事件都是通知。宿主回调返回“OK”不能在设备上批准操作。用户取消时,取消对应连接上的 SDK 操作,并使待处理 UI 回调失效。
地址确认和签名应使用同一个明确的标准/隐藏钱包绑定。不要将宿主端输入的 PIN 或密码短语写入日志或持久化存储。
验证与恢复
测试权限拒绝、蓝牙关闭、特征缺失、通知订阅失败、设备输入、取消和重连。让用户在真实设备上确认一个地址,再判断桥接是否可用。
超时后不要自动重放签名或固件升级。参见断线与重连。