Skip to Content
硬件接入迁移指引升级到 Hardware SDK 1.2

升级到 Hardware SDK 1.2

将现有 Hardware SDK 1.1.x 接入升级到 1.2.x。保留一个 SDK 入口即可,Protocol V2 支持不需要再接一套 SDK。新项目请从快速开始入手。

**接入 Protocol V2 必改:**替换仅支持 V1 的设备读取接口,并核对每个方法的机型、固件和协议支持。**推荐:**新代码使用明确的钱包选择。**兼容项:**可保留已有且受支持的链调用;getPassphraseState 在两种协议上仍作为已废弃的兼容辅助接口保留。**按需处理:**Bridge 转 WebUSB、更换 SDK 入口和实现固件升级,都属于独立的接入选择。

什么没变

  • 方法仍返回 { success, payload },先检查 success 再使用成功结果。失败通过 payload.error 和存在时的 payload.code 表达。
  • evmGetAddress、btcSignTransaction 等链方法保留公开调用形式:HardwareSDK.method(connectId, deviceId?, params)。是否可用仍取决于设备和固件。
  • init({ env }) 选择传输方式,不选择 Protocol V1 或 V2。keepSession 仍控制传输持有,不选择钱包。

升级包

保留适合当前运行时的入口包。对已有 common-connect 接入,下方命令选择 1.2 版本线并精确保存解析后的版本;要可复现地上线,请把 1.2 换成已验收的完整版本号。

npm i --save-exact @onekeyfe/[email protected]

所有直接安装的 @onekeyfe/hd-* 包都钉到同一个完整版本,包括共享类型和传输包;提交锁文件并核对实际依赖树。测试预发布版本时显式选择 alpha 版本。使用某个 1.2.x 版本不代表包含后续补丁新增的全部方法,仍需查看各 API 的最低 SDK 与固件版本。

使用 @onekeyfe/hd-web-sdk 时,省略 connectSrc,采用安装包默认的 iframe URL。如果覆盖或自行托管该地址,要部署兼容且匹配的 iframe 资源,验证 URL 可访问、CSP 放行且初始化成功。npm 发布成功不代表托管 iframe 已可用。上线与回退时,将包和 iframe 作为同一版本一起处理。

不要在同一运行时同时加载 @onekeyfe/hd-web-sdk 和 @onekeyfe/hd-common-connect-sdk。原生接入还需用所选 SDK 版本验证已安装的传输插件与权限,见快速开始。

要替换的 API

现有接入迁移目标何时修改
getFeatures()getDeviceState()两种协议统一读取时使用;旧接口仅支持 V1
getOnekeyFeatures()getDeviceState({ scope: 'firmware' })V2 使用统一身份与版本快照
getPassphraseState()openWalletSession({ mode })新接入使用明确的钱包选择;旧辅助接口保留兼容用途
存储固件 session_id改存钱包绑定固件会话 ID 由 SDK 内部管理
keepSession保留现有传输用法不要换成钱包会话参数
env: 'web' + Bridgeenv: 'webusb'仅在独立迁移传输时处理,见传输章节
Pro 2 / Neo 固件流程firmwareUpdateV4仅当应用实现这些设备的固件升级时处理

没有 openWalletSession({ mode: 'resume-hidden' })。后续方法携带 passphraseState,即可恢复已有隐藏钱包绑定。

1. 设备快照

1.1.x

const features = await HardwareSDK.getFeatures(connectId); if (!features.success) throw new Error(features.payload.error); const deviceId = features.payload.device_id;

1.2.x

const state = await HardwareSDK.getDeviceState(connectId); if (!state.success) throw new Error(state.payload.error); const deviceId = state.payload.identity.deviceId; if (!deviceId) throw new Error('Device has no wallet identity');
旧字段或旧假设统一字段 / 规则
device_ididentity.deviceId:钱包/种子身份,可能为空
onekey_serial_no / 发现结果中的 uuididentity.serialNo / 发现结果中的 serialNo:物理身份;uuid 已废弃
label、onekey_ble_nameidentity.label、identity.bleName
initialized、unlocked、pin_protection、passphrase_protectionstatus.initialized、status.unlocked、status.pinProtection、status.passphraseProtection
language 与蓝牙设置settings.language、settings.bleEnabled
固件 / Bootloader / 蓝牙版本字段versions.firmware、versions.bootloader、versions.ble:字符串或 null

默认 scope: 'runtime' 刷新状态;scope: 'settings' 刷新状态与设置;scope: 'firmware' 刷新状态、身份、版本及验证信息。返回的是完整快照,不是只有被刷新的部分。当前模式下某些字段可能不可用:保留 null,不要转换成 false 或 0.0.0。V2 Bootloader / Romloader 模式不支持读取设置。

先确认 searchDevices 成功,再读取列表。connectId 是当前传输句柄,重连后可能变化。不要用序列号替代缺失的 deviceId,也不要用硬件序列号绑定钱包。见标识符和设备状态。

2. 钱包会话

1.1.x — 选择隐藏钱包,之后携带指纹:

const ps = await HardwareSDK.getPassphraseState(connectId, { initSession: true, }); if (!ps.success) throw new Error(ps.payload.error); if (typeof ps.payload !== 'string' || !ps.payload) { throw new Error('No hidden wallet fingerprint'); } const address = await HardwareSDK.evmGetAddress(connectId, deviceId, { path: "m/44'/60'/0'/0/0", passphraseState: ps.payload, }); if (!address.success) throw new Error(address.payload.error);

1.2.x — 按用户选择执行下列流程中的一种,不要依次执行两种。

标准钱包

import { OpenWalletSessionMode } from '@onekeyfe/hd-core'; const opened = await HardwareSDK.openWalletSession(connectId, { mode: OpenWalletSessionMode.Standard, }); if (!opened.success) throw new Error(opened.payload.error); if (opened.payload.walletType !== 'standard') { throw new Error('A standard wallet was not opened'); } const address = await HardwareSDK.evmGetAddress(connectId, opened.payload.deviceId, { path: "m/44'/60'/0'/0/0", useEmptyPassphrase: true, }); if (!address.success) throw new Error(address.payload.error);

隐藏钱包

import { OpenWalletSessionMode } from '@onekeyfe/hd-core'; const opened = await HardwareSDK.openWalletSession(connectId, { mode: OpenWalletSessionMode.SelectHidden, }); if (!opened.success) throw new Error(opened.payload.error); if (opened.payload.walletType !== 'hidden' || !opened.payload.passphraseState) { throw new Error('A hidden wallet was not opened'); } const binding = opened.payload; const address = await HardwareSDK.evmGetAddress(connectId, binding.deviceId, { path: "m/44'/60'/0'/0/0", passphraseState: binding.passphraseState, }); if (!address.success) throw new Error(address.payload.error);

检查成功结果和钱包类型后,才保存返回的 walletType、deviceId 与 passphraseState。标准钱包的指纹为 null。V1 关闭 passphrase 保护时,选择隐藏钱包也可能返回标准钱包,不能把它存成隐藏钱包。

不要向 openWalletSession 传入旧参数 useEmptyPassphrase、initSession、deviceId 或 passphraseState,包括继承的值为 false 的默认项。后续地址/签名调用,标准钱包使用 useEmptyPassphrase: true,隐藏钱包使用已保存的 passphraseState。隐藏钱包漏传指纹时,可能在标准钱包上成功而不报错。

不要在每次方法前或重连后自动重新选择钱包。复用已有绑定;身份或指纹验证失败时停止,让用户明确选择钱包。不要用新连接设备覆盖原绑定。见钱包会话。

UI、取消与重连

事件宿主处理
REQUEST_PIN仅宿主输入时回复 UI_RESPONSE.RECEIVE_PIN;设备端 PIN 提示无需回复
REQUEST_PASSPHRASE宿主输入时回复 UI_RESPONSE.RECEIVE_PASSPHRASE;选择设备输入使用 value: "" 和 passphraseOnDevice: true。设备端通知无需回复
REQUEST_PASSPHRASE_ON_DEVICE、REQUEST_BUTTON提示用户,不发送输入响应
关闭窗口 / 进度通知更新 UI,不代表方法成功

方法 Promise 才是最终结果。用 payload.code 分类错误,不要匹配本地化错误文案;区分参数非法、方法不支持、钱包不匹配、取消和传输失败。

UI_EVENT 监听器收到含类型与载荷的消息包装。DEVICE.STATE 监听器直接收到状态事件载荷,包括 connectId、state 与 revision,不能按同一种结构处理。只订阅一次,接入页面卸载时移除监听器。

同一设备的方法串行执行,不同设备的宿主 PIN/passphrase 弹窗也要串行。当前公共入口的 uiResponse 只转发 type 和 payload,不能假设顶层关联元数据会传到 SDK。关闭、取消、断连后使旧弹窗回调失效,避免回复之后的新请求。

用 HardwareSDK.cancel(connectId) 取消当前操作,并尊重用户取消。断连后重新发现设备、获取当前传输句柄、读取状态并复用已验证的钱包绑定。不要自动重放签名、擦除或固件升级。普通断连无需 dispose;明确释放 SDK 后,调用前需重新初始化。见核心接口指南和重连。

3. Protocol V1 与 V2

Classic / Mini / Touch / Pro 使用 Protocol V1,Pro 2 / Neo 使用 Protocol V2。SDK 通过现场探测识别协议,不要从 USB PID、蓝牙名或外壳推断。

通常由 SDK 探测选择协议。传入 connectProtocol 时表示严格期望,协议不符会拒绝。SDK 版本、协议支持和设备最低固件是独立检查项,启用方法前需核对 API 支持表。

仅 V1 的链(Stellar、Alephium、Nexa、Dynex、Nervos、SCDO、Benfen 和 Neo 链)不支持 Pro 2 / Neo。Neo 设备名不代表支持 Neo 链。见协议和链支持。

4. 固件

设备升级 API
Classic / Mini / TouchfirmwareUpdateV2
ProfirmwareUpdateV3
Pro 2 / NeofirmwareUpdateV4

如果接入负责固件升级,也要更新版本检查结果的解析:V2 协议的发布结果可能包含组件目标和资源归档,不能假设只有一个旧格式二进制,也不能假设 URL/指纹一定存在。使用与机型匹配的发布资源,遵循所选升级 API 的契约。

收到应答或进度事件不代表安装完成。重启后重连,读取 scope: 'firmware' 核实安装版本。需要时保留原有 keepSession 传输持有,断连后绝不自动重放升级。见固件升级。

5. 传输

从 1.1.x 升到 1.2.x 本身不要求更换可用的传输。如果同时决定将 Bridge(env: 'web' + checkBridgeStatus)迁到 WebUSB,请使用独立指南:

WebUSB 需要安全上下文及用户手势来选择授权。BLE 需要系统蓝牙权限。应在实际发布的浏览器、Electron 或原生运行时中验证。

检查清单

  1. 选定完整版本,对齐 SDK 依赖和 iframe 资源,保留旧锁文件与发布资源。
  2. 更新状态读取与空值处理;需要 V2 支持时替换旧读取接口。
  3. 更新钱包选择并保存验证后的绑定;不要将传输句柄、固件会话 ID 当作钱包身份。
  4. 更新输入/通知、取消与重连处理;串行执行设备方法及宿主输入弹窗。
  5. 核对协议、链与固件支持;仅当接入负责固件流程时迁移升级处理。

上线前在每种支持的运行时执行下列验收用例。硬件用例需真机验证,文档构建成功不等于硬件测试通过。

用例预期结果
在已有 V1 与受支持 V2 设备上初始化、发现传输/协议正确;返回统一状态或可处理错误,不虚构身份
标准、隐藏钱包;V1 关闭 passphrase钱包类型和地址正确;标准指纹为空,隐藏钱包绑定已验证
复用隐藏绑定;切换设备/种子或传错指纹有效绑定仍对应原钱包;不匹配时停止,不覆盖绑定
宿主/设备 PIN 与 passphrase;确认、取消、关闭仅输入请求收到响应;由 Promise 判定完成;忽略旧回调
断连/重连与双设备刷新传输句柄、串行输入、保留已验证绑定,不重放副作用
不支持的链、协议或旧固件正确处理支持性错误,不悄悄切换钱包/协议
自定义 iframe / 原生传输资源、权限与固定版本匹配;初始化及一次受支持的地址调用成功
固件流程(如已实现)机型/资源正确;重连后核实安装版本

与 1.1.x 基线比较已知钱包地址及受支持的签名结果,按错误码检查失败。不要把 PIN、passphrase、派生秘密或私密材料写入日志或测试样本。

回退

将原有精确依赖、锁文件、iframe 资源与运行时配置保留为一套已测试的发布版本。回退时一起恢复,不要将 1.1.x 入口包与 1.2.x 资源或类型混用。

回到 1.1.x 基线时,关闭新启用的仅 V2 接入。SDK 降级不等于固件降级。保留钱包绑定数据,但需用恢复后的接入验证;无法验证时让用户选择。不要自动回落到标准钱包,也不要重放已取消的操作。

下一步

最后更新于