核心接口说明
这里汇总 UKey Wallet Hardware SDK 的通用调用方式。你可以从这里了解设备标识如何获取、请求如何串行执行、UI 事件如何响应,以及不同链接口在参数和错误处理上的共性要求。
速览流程
- 调用形式:示例里通常把 SDK 入口命名为
ukeySdk,因此调用会写成ukeySdk.method(connectId, deviceId?, params),返回Promise<{ success, payload }>;读取payload前先确认success。 - 设备标识:
connectId来自searchDevices,用于定位连接;deviceId来自getFeatures,用于确认当前钱包状态。BLE 场景通常必须传入deviceId,WebUSB 场景也建议携带。 - 交互事件:应用入口订阅一次
UI_EVENT即可。只有 PIN、Passphrase、Bootloader 设备选择等需要用户输入的事件才调用uiResponse。 - 链接校验:HD Path 按链校验;隐藏钱包场景使用
initSession + passphraseState;同一设备上的请求保持串行,避免传输层互相抢占。
const opResult = await ukeySdk.evmGetAddress(connectId, deviceId, {
path: "m/44'/60'/4'/0/1",
});
if (!opResult.success) throw new Error(opResult.payload.error);
console.log(opResult.payload.address);
交互图示

核心标识环境
| 名称 | 用途 | 来源 | 说明 |
|---|---|---|---|
connectId | 连接标识,用来把请求路由到具体设备 | searchDevices() | 同一设备通常保持稳定;WebUSB/Bridge 多数情况下对应序列号;BLE 使用系统层标识(Android MAC / iOS UUID)。 |
deviceId | 当前钱包状态标识 | getFeatures(connectId) | 设备重置、擦除、恢复或更换种子后会变化;敏感操作会借此避免请求发到错误钱包。 |
- 建议把
connectId和deviceId成对缓存;出现DeviceCheckDeviceIdError、用户恢复设备或切换设备时,重新调用getFeatures。 - SDK 相关包需要版本一致:
@ukeyfe/hardware-common-connect-sdk、@ukeyfe/hardware-core、@ukeyfe/hardware-shared应与固件和 Bridge 能力保持匹配。 - WebUSB 需要 HTTPS 和用户手势;React Native BLE 需要蓝牙及平台权限;
lowlevel环境需要宿主自行实现 64 字节帧收发。 - Bootloader 模式下只有部分固件接口可用;使用 Bridge 时请确认 Bridge 正在运行且端口未被其他程序占用。
接口标识要求
| 标识组合 | 用途说明 | 常见接口 |
|---|---|---|
| 🟢 无需标识 | SDK 初始化、配置、事件管理 | init on/off searchDevices getLogs dispose uiResponse |
🟡 仅需 connectId | 设备管理、状态查询、固件操作 | getFeatures getPassphraseState cancel deviceSettings deviceReset |
🔵 需要 connectId + deviceId | 区块链签名、地址派生、加解密 | evmSignTransaction btcSignTransaction solanaSignMessage allNetworkGetAddress |
建议调用顺序
建议按固定顺序组织请求:初始化 SDK → 搜索设备 → 读取设备信息 → 订阅 UI 事件 → 执行具体操作 → 释放或清理资源。
import ukeySdk, {
UI_EVENT,
UI_REQUEST,
UI_RESPONSE,
} from "@ukeyfe/hardware-common-connect-sdk";
// 1. 先初始化 SDK(应用入口跑一次就够)
await ukeySdk.init({ env: "webusb", fetchConfig: true, debug: false });
// 2. 搜索当前已经连上的设备
const availableDevices = await ukeySdk.searchDevices();
if (!availableDevices.length) throw new Error("No device");
const [{ connectId }] = availableDevices;
// 3. 读取设备信息(BLE 必做,WebUSB 建议做)
const featureInfo = await ukeySdk.getFeatures(connectId);
const deviceId = featureInfo?.payload?.device_id;
// 4. 监听 UI 事件
ukeySdk.on(UI_REQUEST.REQUEST_PIN, () => {
// 拉起 PIN 输入界面,拿到输入后再调用 uiResponse
});
ukeySdk.on(UI_REQUEST.REQUEST_PASSPHRASE, () => {
// 拉起 Passphrase 输入界面
});
// 5. 执行链上操作(这里以 EVM 签名举例)
await ukeySdk.evmSignTransaction(connectId, deviceId, {
path: "m/44'/60'/4'/0/1",
});
调用提醒:面向同一台设备时,把硬件请求排队执行;用户切到另一台设备后,先重新读取一次 getFeatures;页面销毁前记得解绑事件监听;只有确实要重置传输上下文或结束 SDK 会话时,才调用 ukeySdk.dispose()。
参数说明
常见入参(CommonParams)
| 字段 | 用途说明 | 典型场景 |
|---|---|---|
initSession?: boolean | 主动建立硬件会话,可配合 Passphrase 状态使用 | 首次操作前预热会话,减少后续交互 |
passphraseState?: string | 隐藏钱包会话标识 | 连续使用同一个隐藏钱包时携带 |
useEmptyPassphrase?: boolean | 强制使用标准钱包 | 避免误进入隐藏钱包 |
deriveCardano?: boolean | 提前派生 Cardano 相关数据 | 会话内首次 Cardano 操作 |
retryCount? / pollIntervalTime? / timeout? | 调整轮询与超时策略 | BLE 或网络状态不稳定时 |
detectBootloaderDevice?: boolean | 检测到 Bootloader 设备时快速返回 | 引导用户退出 Bootloader |
skipWebDevicePrompt?: boolean | 跳过 WebUSB 选择弹窗 | 复用已经授权的 WebUSB 设备 |
keepSession? | 已不建议继续使用 | 优先改用会话和 Passphrase 状态 |
组合参考片段:
// 隐藏钱包并连续调用,避免反复弹提示
const sessionOptions = {
initSession: true,
keepSession: true,
passphraseState: "hidden-wallet-id",
};
await ukeySdk.evmSignMessage(connectId, deviceId, {
path: "m/44'/60'/4'/0/1",
messageHex,
...sessionOptions,
});
传输方式差异
| 传输方式 | 典型入口 | 主要差异 | 适合场景 |
|---|---|---|---|
| WebUSB | env: "webusb" + @ukeyfe/hardware-common-connect-sdk | 纯浏览器接入,不需要原生桥接;依赖 HTTPS 和用户手势 | Web 站点、后台控制台、浏览器 DApp |
| React Native BLE | env: "react-native" + @ukeyfe/hardware-ble-sdk + @ukeyfe/hardware-transport-react-native | 需要 BLE 原生模块和平台权限;由 RN 侧负责扫描、连接和收发 | 纯 React Native App |
| iOS 原生低层接入 | env: "lowlevel" + WKWebViewJavascriptBridge + CoreBluetooth | JS 运行在 WebView,BLE 由原生侧处理,再通过桥接回传 | iOS 原生壳 + Web 业务层 |
| Android 原生低层接入 | env: "lowlevel" + WebView + JSBridge + Nordic BLE | JS 同样保留在 WebView,Android 侧负责配对、连接、通知和回传 | Android 原生壳 + Web 业务层 |
这些方式的链 API 调用形状是一样的,差别主要在初始化方式、权限要求和底层传输实现。
常见组合
- Web 站点 + WebUSB:最轻量,适合浏览器直连设备。
- React Native App + BLE:适合纯 RN 项目,需要本地 BLE 能力。
- iOS 原生壳 + WebView + CoreBluetooth:适合保留 Web 业务层,同时由原生侧接管 BLE。
- Android 原生壳 + WebView + Nordic BLE:与 iOS 方案类似,适合原生容器承载 Web 页面。
- 隐藏钱包连续操作 + 任意传输方式:建议配合
initSession + passphraseState,减少重复确认。
代码示例
// WebUSB
await ukeySdk.init({ env: "webusb", fetchConfig: true, debug: false });
// React Native BLE
await ukeySdk.init({ env: "react-native", fetchConfig: true, debug: __DEV__ });
// iOS / Android 原生低层接入
await ukeySdk.init({ env: "lowlevel", debug: true });
HD Path 规则
path 支持字符串或数组形式:path: string | number[]。大多数链遵循 BIP44 思路,不同曲线对路径硬化要求不同;例如 Solana、NEAR 等 ed25519 链通常需要全硬化路径。
路径速查:
EVM:m/44'/60'/6'/0/2,标准 EVM 账户最常用。BTC (Nested SegWit):m/49'/0'/0'/0/0;如果是 Native SegWit,通常会走84'。Solana:m/44'/501'/3'/0',这类 ed25519 链一般要求全硬化。NEAR:m/44'/397'/0'/0'/1',同样属于全硬化路径。Cardano:m/1852'/1815'/1'/0/1,质押相关路径常见为.../2/0。TRON:m/44'/195'/1'/0/1,路径风格和 EVM 比较接近。
如果改用数组传路径,硬化层级需要带上 0x80000000 标记,例如:[(44 | 0x80000000) >>> 0, (0 | 0x80000000) >>> 0, 0x80000000, 0, 0]。
如果设备返回 "forbidden path",通常是路径长度、coin type 或硬化标记不符合该链要求。请以对应链 API 页面中的路径规则为准。
事件说明
SDK 会通过事件把设备状态和用户交互需求传给应用,常用通道如下:
| 事件通道 | 说明 |
|---|---|
UI_EVENT | 用户交互提示(PIN、Passphrase 等) |
DEVICE_EVENT | 设备状态变化(连接、断开、能力更新等) |
FIRMWARE_EVENT | 固件升级信息 |
只有需要应用回传输入内容的
UI_REQUEST才调用uiResponse。纯提示类事件用于更新界面即可。多设备场景下,请根据事件中的设备标识把提示路由到对应设备。
需回传的 UI 请求
| 请求类别 | 触发时机 | 返回结果 |
|---|---|---|
REQUEST_PIN | 受保护调用且设备被锁定 | UI_RESPONSE.RECEIVE_PIN(软件盲输或硬件端输入) |
REQUEST_PASSPHRASE | 软件输入隐藏钱包口令 | UI_RESPONSE.RECEIVE_PASSPHRASE(value、passphraseOnDevice、attachPinOnDevice、save) |
REQUEST_PASSPHRASE_ON_DEVICE | 隐藏钱包口令交由硬件端输入 | UI_RESPONSE.RECEIVE_PASSPHRASE(passphraseOnDevice: true) |
REQUEST_DEVICE_IN_BOOTLOADER_FOR_WEB_DEVICE | Web Bootloader 设备选择 | UI_RESPONSE.SELECT_DEVICE_IN_BOOTLOADER_FOR_WEB_DEVICE(deviceId) |
展示类 UI 请求
| 请求类别 | 用途 |
|---|---|
REQUEST_BUTTON | 在设备上提示确认 |
DEVICE_PROGRESS | 长任务进度 |
FIRMWARE_PROCESSING / FIRMWARE_PROGRESS / FIRMWARE_TIP | 固件升级或处理状态 |
BLUETOOTH_PERMISSION / LOCATION_PERMISSION | BLE 权限提醒 |
BOOTLOADER / REQUIRE_MODE / NOT_INITIALIZE / FIRMWARE_NOT_SUPPORTED | 模式/支持性提示 |
关键设备/固件事件
设备状态
CONNECT:设备接入且可用,刷新设备列表并自动选中。DISCONNECT:设备拔出或 BLE 断开,标记会话失效并提示重新连接。ACQUIRE:传输会话开始,阻塞并发请求并标记设备忙。RELEASE:传输会话结束,放行队列中的下一个请求。CHANGED:功能状态变更(如解锁后),重新执行getFeatures刷新缓存的deviceId。USED_ELSEWHERE:发现传输冲突,提示关闭其他应用/Bridge。UNREADABLE:权限或驱动异常,提示重新授权或检查驱动。
交互请求
BUTTON:设备等待确认,UI 显示“请在设备确认”。PIN:设备等待 PIN,继续 PIN 输入流程。PASSPHRASE:设备等待软件口令,继续口令输入流程。PASSPHRASE_ON_DEVICE:设备等待在机输入口令,提示用户在设备上输入。SELECT_DEVICE_IN_BOOTLOADER_FOR_WEB_DEVICE:Bootloader 设备选择中,保持设备选择界面直至完成。
固件消息
FEATURES:能力快照,用于缓存能力信息。SUPPORT_FEATURES:支持矩阵快照,用于缓存支持情况。RELEASE_INFO:新固件信息,在安全时机提示升级。BLE_RELEASE_INFO:新 BLE 固件信息,在安全时机提示升级。
事件处理范例
import ukeySdk, {
UI_EVENT,
UI_REQUEST,
UI_RESPONSE,
} from "@ukeyfe/hardware-common-connect-sdk";
const routeUiRequest = (uiEvent: any) => {
switch (uiEvent.type) {
case UI_REQUEST.REQUEST_PIN:
promptForPin(({ value }) =>
ukeySdk.uiResponse({
type: UI_RESPONSE.RECEIVE_PIN,
payload: value,
}),
);
return;
case UI_REQUEST.REQUEST_PASSPHRASE:
promptForPassphrase(({ value, onDevice, save }) =>
ukeySdk.uiResponse({
type: UI_RESPONSE.RECEIVE_PASSPHRASE,
payload: {
value,
passphraseOnDevice: onDevice,
attachPinOnDevice: false,
save,
},
}),
);
return;
case UI_REQUEST.REQUEST_DEVICE_IN_BOOTLOADER_FOR_WEB_DEVICE:
presentDeviceChoices((deviceId) =>
ukeySdk.uiResponse({
type: UI_RESPONSE.SELECT_DEVICE_IN_BOOTLOADER_FOR_WEB_DEVICE,
payload: { deviceId },
}),
);
return;
default:
console.log("收到的 UI 事件", uiEvent.type, uiEvent.payload);
}
};
ukeySdk.on(UI_EVENT, routeUiRequest);
输入安全
PIN 输入
- UKey Core 26:仅支持设备端输入
- UKey Lite 24 / Lite 25:支持盲输模式,但建议优先使用设备端输入
const PIN_KEYPAD_MAP = ["7", "8", "9", "4", "5", "6", "1", "2", "3"];
const keypadSlot = 1;
ukeySdk.uiResponse({
type: UI_RESPONSE.RECEIVE_PIN,
payload: PIN_KEYPAD_MAP[keypadSlot - 1],
});
Passphrase 输入
- 标准钱包:等同于空口令路径,通常是默认选择。
- 隐藏钱包:需要输入非空口令,且大小写会影响结果。
| 输入方案 | 传参 | 安全说明 |
|---|---|---|
| 硬件端完成(优先采用) | passphraseOnDevice: true | 口令不经过应用侧,安全性最高 |
| 软件端输入 | { value, passphraseOnDevice: false, save: true } | 仅在当前会话内使用,勿持久化明文 |
| 强制标准钱包 | useEmptyPassphrase: true | 明确不进入隐藏钱包 |
异常处理
| 错误分组 | 典型原因 | 建议 |
|---|---|---|
| Device (101–118, 200) | 模式错误、设备忙、device_id 不匹配、未初始化 | 先把设备切回正确模式,再重连并重试 init + getFeatures |
| IFrame (300–305) | 未 init、加载/超时/被拦截 | 确保 init 成功且未被 CSP/istack 阻挡 |
| Method/Firmware (400–418) | 入参错误、需固件升级、禁用路径说明 | 校验入参/HD Path,提示升级固件 |
| Transport (600–603) | 传输未配置、并发调用、protobuf 错误 | 核验 env/Bridge,串行调用,对齐 SDK 版本要求 |
| Bluetooth (700–722) | 扫描/权限/连接/超时 | 核验蓝牙/定位权限与电量距离,重试连接 |
| Runtime/Bridge (800–821) | PIN/动作被取消、Bridge 权限/超时、盲签关闭 | 重试或提示安装/启动 Bridge,确保签名模式 |
| Web device (901–902) | WebUSB/蓝牙授权缺失,或选择弹窗未能拉起 | 重新请求授权,并确认 HTTPS 与用户手势条件满足 |
完整错误定义和 payload 结构可参考 HardwareError.ts。
处理建议:在应用内维护错误码到用户提示的映射表,并提供重试、检查设备、升级固件等明确操作,避免只显示底层错误文本。
继续阅读
- 传输适配 - WebUSB、React Native BLE、iOS/Android 底层接入
- 链 API - 地址派生、消息签名、交易签名等链级接口
- 迁移指南 - 从旧 Bridge 接入迁移到 common-connect