跳到主要内容

导读

这份文档面向正在把 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-sdkWebUSB说明
React Native蓝牙@ukeyfe/hardware-ble-sdkRN 蓝牙
Android(原生)蓝牙@ukeyfe/hardware-common-connect-sdk安卓原生蓝牙
iOS(原生)蓝牙@ukeyfe/hardware-common-connect-sdkiOS原生蓝牙
Flutter蓝牙@ukeyfe/hardware-common-connect-sdkFlutter原生蓝牙
UKey Wallet SDK 集成流程图

如果你需要自己实现原生通道,请参考:传输插件(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-nativeReact 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);

兼容表

下面的矩阵用于快速判断不同型号支持哪些连接方式:

设备蓝牙USBAir-Gap
UKey Lite 24
UKey Lite 24
UKey Lite 24
SupportedSupportedN/A
UKey Lite 25
UKey Lite 25
UKey Lite 25
SupportedSupportedN/A
UKey Core 26
UKey Core 26
UKey Core 26
SupportedSupportedSupported

Air-Gap 模式: UKey Core 26 可通过二维码交换数据完成离线签名,不需要保持 USB 或蓝牙连接。详见 Air-Gap 集成

核心包组

包名用途NPM
@ukeyfe/hardware-common-connect-sdkWebUSB 和原生桥接场景的统一 SDK 入口,建议优先使用npm
@ukeyfe/hardware-ble-sdkReact Native 项目使用的 BLE 连接与通信能力npm
@ukeyfe/hardware-transport-react-nativeReact Native 传输层桥接与副用途处理npm
@ukeyfe/hd-transport-web-deviceWeb 环境中访问硬件设备的传输层实现npm
@ukeyfe/hd-transport-emulator模拟器传输层,适合无设备开发和自动化调试npm
@ukeyfe/hd-transport-http通过 HTTP 桥接硬件通信的传输层npm
@ukeyfe/hd-transport-lowlevel自定义原生宿主需要实现的底层适配器契约npm
@ukeyfe/hardware-coreSDK 事件、常量和消息流转的核心定义npm
@ukeyfe/hardware-shared各 SDK 共享的类别、过滤器和工具方法npm

进阶主题

  • 如果你需要调试底层传输、排查消息收发问题,或接入自定义宿主通道,可以继续阅读:传输插件(Low-level)

帮助

本文档主要服务于开发集成。如果你遇到的是产品使用问题,请优先查看帮助中心;如果是 SDK 集成问题,可以在 GitHub 中讨论或确认提交 issue。

相关库