导读
这份文档面向正在把 UKey Wallet 硬件能力接入 Web、桌面端或移动端应用的开发者。你可以从这里了解 SDK 的入口选择、设备连接方式、初始化流程、用户交互事件,以及如何发起第一笔签名请求。
选连接
先根据运行环境确定传输层。新的 USB/WebUSB 集成建议优先使用 @ukeyfe/hardware-common-connect-sdk;只有在项目仍依赖 iframe 插件宿主时,才继续使用 @ukeyfe/hardware-web-sdk。
连接形式
| 方式 | 说明 | 支持机型 |
|---|---|---|
| USB / WebUSB | 通过 USB 线连接设备;浏览器使用 WebUSB,原生应用可通过底层插件转发数据 | 所有 UKey Wallet 设备 |
| Bluetooth BLE(原生) | 用于原生 App 的蓝牙连接;不依赖 Web Bluetooth,需要系统蓝牙权限 | UKey Lite 24、UKey Lite 25、UKey Core 26 |
| Air-Gap(二维码) | 通过二维码交换待签名数据和签名结果,适合不保持在线通道的场景 | 仅 UKey Core 26 |
平台表
| 平台(技术栈) | 传输协议 | SDK 包 | 说明页 |
|---|---|---|---|
| Web(浏览器) | WebUSB | @ukeyfe/hardware-common-connect-sdk | WebUSB说明 |
| React Native | 蓝牙 | @ukeyfe/hardware-ble-sdk | RN 蓝牙 |
| Android(原生) | 蓝牙 | @ukeyfe/hardware-common-connect-sdk | 安卓原生蓝牙 |
| iOS(原生) | 蓝牙 | @ukeyfe/hardware-common-connect-sdk | iOS原生蓝牙 |
| Flutter | 蓝牙 | @ukeyfe/hardware-common-connect-sdk | Flutter原生蓝牙 |

如果你需要自己实现原生通道,请参考:传输插件(Low-level)
装 SDK
按照目标运行时安装对应的 SDK 入口,避免在同一个场景中混用多套入口:
# 浏览器或桌面端 WebUSB 接入(优先)
npm i @ukeyfe/hardware-common-connect-sdk
# React Native BLE 入口
npm i @ukeyfe/hardware-ble-sdk
# 原生 App 承载底层插件通道(Android/iOS/Flutter)
npm i @ukeyfe/hardware-common-connect-sdk
# iframe 插件侧专用包(仅插件环境)
npm i @ukeyfe/hardware-web-sdk
各传输方式的详细接入说明:
- WebUSB 项目请从 WebUSB说明 开始。
- React Native 蓝牙项目请参考 RN 蓝牙。
- Android、iOS、Flutter 原生宿主通常由原生层负责 BLE,再通过底层传输插件暴露给 JS。
- 自定义宿主或特殊链路请实现 传输插件(Low-level)。
启 SDK
初始化时需要明确当前使用的传输环境。除非你正在做迁移兼容层,否则不要在一个运行时里同时混用多个 SDK 入口。
浏览器与桌面 WebUSB
使用 @ukeyfe/hardware-common-connect-sdk:
import ukeySdk from "@ukeyfe/hardware-common-connect-sdk";
await ukeySdk.init({
env: "webusb",
debug: process.env.NODE_ENV !== "production",
fetchConfig: true,
});
React Native BLE 入口
使用 @ukeyfe/hardware-ble-sdk:
import ukeySdk from "@ukeyfe/hardware-ble-sdk";
await ukeySdk.init({
debug: __DEV__,
});
原生宿主与底层通道
使用 @ukeyfe/hardware-common-connect-sdk:
import ukeySdk from "@ukeyfe/hardware-common-connect-sdk";
await ukeySdk.init({
env: "lowlevel",
debug: process.env.NODE_ENV !== "production",
fetchConfig: true,
});
| 环境 | 使用场景 |
|---|---|
webusb | 浏览器直接通过 WebUSB 访问设备,不需要 istack |
lowlevel | 原生宿主实现底层适配器,再把收发能力桥接给 JS |
react-native | React Native 或 Electron 类场景中的 BLE 集成 |
emulator | 使用模拟器完成开发和调试,不依赖真实设备 |
Iframe 插件运行环境
使用 @ukeyfe/hardware-web-sdk(插件侧专用):
import HardwareWebSdk from "@ukeyfe/hardware-web-sdk";
const iframeSdk = HardwareWebSdk.HardwareWebSdk;
await iframeSdk.init({
debug: process.env.NODE_ENV !== "production",
connectSrc: "https://jssdk.demo.example/1.1.19/", // iframe 宿主地址
});
挂事件
在发起受保护请求之前,先绑定事件监听。设备插拔、PIN、Passphrase、确认弹窗等交互都会通过事件通道通知应用。
import { UI_EVENT, UI_REQUEST, DEVICE } from "@ukeyfe/hardware-core";
ukeySdk.on(UI_EVENT, async (message) => {
switch (message.type) {
case UI_REQUEST.REQUEST_PIN:
// 在这里接收并回传 PIN(后文有参考)
break;
case UI_REQUEST.REQUEST_PASSPHRASE:
// 在这里处理口令输入(后文有参考)
break;
}
});
ukeySdk.on(DEVICE.CONNECT, (payload) => console.log("连接事件详情:", payload));
ukeySdk.on(DEVICE.DISCONNECT, (payload) => console.log("断开事件详情:", payload));
找设备
申请USB访问
import { UKEY_WEBUSB_FILTER } from "@ukeyfe/hardware-shared";
// 通过点击等明确动作拉起浏览器的 USB 设备选择器。
await navigator.usb.requestDevice({ filters: UKEY_WEBUSB_FILTER });
查设备
const callResult = await ukeySdk.searchDevices();
if (!callResult.success) throw new Error(callResult.payload.error);
const availableDevices = callResult.payload;
// 返回结果参考片段:[{ connectId, deviceId?, name, deviceType, ... }]
读设备
当你需要设备身份、固件信息,或 BLE 调用所需的最新 device_id 时,调用 getFeatures:
const featureInfo = await ukeySdk.getFeatures(connectId);
if (!featureInfo.success) throw new Error(featureInfo.payload.error);
const deviceId = featureInfo.payload.device_id;
重要:
connectId表示连接通道,通常可以长期保存;device_id表示当前设备身份,设备重置或恢复后可能变化,需要通过getFeatures重新获取。
输 PIN
设备锁定且当前请求需要授权时,SDK 会发出 REQUEST_PIN。更稳妥的做法是把 PIN 输入留在硬件端,避免 PIN 进入宿主应用。
import { UI_RESPONSE } from "@ukeyfe/hardware-core";
// 方案一:把 PIN 留在设备屏幕上输入(推荐先走这条)
await ukeySdk.uiResponse({
type: UI_RESPONSE.RECEIVE_PIN,
payload: "@@UKEY_INPUT_PIN_IN_DEVICE",
});
// 方案二:软件盲输 PIN(UKey Core 26 仅支持在设备端输入)
await ukeySdk.uiResponse({
type: UI_RESPONSE.RECEIVE_PIN,
payload: userInputPin, // 参考输入可以是 '1234'
});
注意: UKey Core 26 的 PIN 只能在硬件端完成;UKey Lite 24、UKey Lite 25 还支持软件侧盲输。
输口令
Passphrase 用于在同一套助记词下选择标准钱包或隐藏钱包。应用可以让用户改在设备上输入,也可以在软件界面中收集并按会话缓存策略处理。
// 方案一:让口令直接在设备上完成输入(最稳妥)
await ukeySdk.uiResponse({
type: UI_RESPONSE.RECEIVE_PASSPHRASE,
payload: { passphraseOnDevice: true, value: "" },
});
// 方案二:用户在软件输入,可以选择会话缓存
await ukeySdk.uiResponse({
type: UI_RESPONSE.RECEIVE_PASSPHRASE,
payload: { value: userPassphrase, passphraseOnDevice: false, save: true },
});
如果某次请求必须使用标准钱包,请在方法参数中传入 useEmptyPassphrase: true,跳过隐藏钱包选择。
首次签名
下面的参考演示如何发起一次 EIP-191 风格的 EVM 消息签名:
const message = "EVM 示例签名消息";
const messageHex = Buffer.from(message).toString("hex");
const opResult = await ukeySdk.evmSignMessage(connectId, deviceId, {
path: "m/44'/60'/5'",
messageHex,
chainId: 1,
});
if (!opResult.success) throw new Error(opResult.payload.error);
console.log("得到的地址结果:", opResult.payload.address);
console.log("返回的签名结果:", opResult.payload.signature);
兼容表
下面的矩阵用于快速判断不同型号支持哪些连接方式:
| 设备 | 蓝牙 | USB | Air-Gap |
|---|---|---|---|
UKey Lite 24 UKey Lite 24 | Supported | Supported | N/A |
UKey Lite 25 UKey Lite 25 | Supported | Supported | N/A |
UKey Core 26 UKey Core 26 | Supported | Supported | Supported |
Air-Gap 模式: UKey Core 26 可通过二维码交换数据完成离线签名,不需要保持 USB 或蓝牙连接。详见 Air-Gap 集成。
核心包组
| 包名 | 用途 | NPM |
|---|---|---|
@ukeyfe/hardware-common-connect-sdk | WebUSB 和原生桥接场景的统一 SDK 入口,建议优先使用 | npm |
@ukeyfe/hardware-ble-sdk | React Native 项目使用的 BLE 连接与通信能力 | npm |
@ukeyfe/hardware-transport-react-native | React Native 传输层桥接与副用途处理 | npm |
@ukeyfe/hd-transport-web-device | Web 环境中访问硬件设备的传输层实现 | npm |
@ukeyfe/hd-transport-emulator | 模拟器传输层,适合无设备开发和自动化调试 | npm |
@ukeyfe/hd-transport-http | 通过 HTTP 桥接硬件通信的传输层 | npm |
@ukeyfe/hd-transport-lowlevel | 自定义原生宿主需要实现的底层适配器契约 | npm |
@ukeyfe/hardware-core | SDK 事件、常量和消息流转的核心定义 | npm |
@ukeyfe/hardware-shared | 各 SDK 共享的类别、过滤器和工具方法 | npm |
进阶主题
- 如果你需要调试底层传输、排查消息收发问题,或接入自定义宿主通道,可以继续阅读:传输插件(Low-level)
帮助
本文档主要服务于开发集成。如果你遇到的是产品使用问题,请优先查看帮助中心;如果是 SDK 集成问题,可以在 GitHub 中讨论或确认提交 issue。