更新记录
1.0.0(2026-11-06) 下载此版本
首个发布版本。
原生桥(app-harmony,21 个导出):基于 @kit.ConnectivityKit 实现适配器开关与状态、扫描起停与设备发现、GATT 建连/断连、服务与特征发现、特征读写、Notify/Indicate 订阅(含 CCCD 写)、连接状态事件、MTU 设置。openBluetoothAdapter 内主动申请 ACCESS_BLUETOOTH,补齐 uni 在鸿蒙缺失的授权弹窗时机;监听类 API 支持多注册方并存、off 按引用移除;同 deviceId 写请求串行 + 5s 单次写超时;错误码严格沿用 uni(微信小程序)蓝牙码表,不自造新码。
JS 兼容层:自动识别静态导入桥与 uni 扁平挂载两种形态,两者都缺时回可读 fail(10001) 不静默;提供与 uni 同名同签名的 harmonyBle 兼容对象及可选全局 polyfill。
插件自带 module.json5 + string.json 声明三项蓝牙权限及用途文案,云打包/本地整包路径下使用者无需另配。
已在真实 BLE 外设(血压计/血糖仪等)真机跑通扫描·连接·服务与特征发现·订阅·读写·断开·重连完整链路。
明确不支持:iBeacon 族 API、onBluetoothAdapterStateChange、经典蓝牙。
平台兼容性
uni-app(4.61)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | - | - | - | - | - | - | API 13 |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - | - | - | - |
har-ble-compat —— uni 蓝牙 API 鸿蒙兼容层
1. 解决的问题
uni-app 的蓝牙 / BLE API 族(uni.openBluetoothAdapter、uni.createBLEConnection、uni.writeBLECharacteristicValue 等)在 HarmonyOS Next 官方兼容性表中为「不支持」:调用不报错,但回调永不触发。表象是"按钮点了没反应",且与权限无关,排查成本极高(DCloud issue #5365)。
本插件做两件事:
- 原生补齐:用
@kit.ConnectivityKit实现蓝牙适配器、扫描、GATT 连接、服务/特征发现、读写、Notify 订阅、连接状态事件、MTU 设置。 - 语义零改写兼容:把 uni 的回调语义、广播数据语义、错误码语义对齐到可整体注入第三方纯 JS 蓝牙 SDK 的程度,存量蓝牙代码无需改写即可在鸿蒙运行。
与市场上已有的鸿蒙 BLE UTS 插件的差异:那些插件暴露的是自己的 API 形状,业务代码要按它的签名重写;本插件的目标是零改写——把 uni 的回调语义、广播数据语义、错误码语义对齐到可以直接把兼容对象整体注入第三方 SDK 的程度。
2. 平台支持
| 平台 | 支持 | 说明 |
|---|---|---|
| app-harmony | √ | 全部能力 |
| app-android | x | 请用 uni 原生蓝牙 API(本就可用) |
| app-ios | x | 同上 |
| H5 / 小程序 | x | 无对应能力,且本插件不含这些端的实现 |
ble-api/ 目录是纯 JS/TS,不含原生代码,可被普通 .ts 安全引用;非鸿蒙端没有原生桥时,兼容层的每个调用都会同步回可读 fail,不会静默挂住。
3. 快速开始
// 1) 引入兼容对象(推荐写法,配合条件编译)
// #ifdef APP-HARMONY
import { harmonyBle } from '@/uni_modules/har-ble-compat/ble-api';
// #endif
// 2) 像用 uni 一样用
harmonyBle.openBluetoothAdapter({
success: () => {
harmonyBle.onBluetoothDeviceFound((res) => {
res.devices.forEach((d: any) => console.log(d.name, d.deviceId, d.RSSI));
});
harmonyBle.startBluetoothDevicesDiscovery({
// 可选:filters / name / namePrefix / allowDuplicatesKey,见第 5 节
allowDuplicatesKey: false,
success: () => console.log('扫描已启动'),
fail: (err: any) => console.log('扫描失败', err.errMsg, err.errCode),
});
},
fail: (err: any) => console.log('蓝牙不可用', err.errMsg, err.errCode),
});
harmonyBle 的每个方法名与参数形状都与 uni 一致,因此可以直接整体当作 uni 的蓝牙子集传给第三方 SDK(见第 7 节)。
4. 目录结构
har-ble-compat/
├── package.json # DCloud 插件元数据(dcloudext / 平台矩阵 / 权限与隐私声明)
├── readme.md
├── changelog.md
├── utssdk/
│ ├── interface.uts # 对外类型契约 + uni 蓝牙错误码常量
│ └── app-harmony/
│ ├── index.uts # @kit.ConnectivityKit 原生实现(21 个导出)
│ ├── module.json5 # 插件自带的权限声明(编译期拷进鸿蒙 module 的 src/main/module.json5)
│ └── resources/base/element/string.json # 权限用途说明字符串(module.json5 的 $string 引用)
└── ble-api/ # JS/TS 兼容层,无原生代码
├── index.ts # 对外入口(re-export 下列三项)
├── transport.ts # 两种传输形态的自动识别与回退
├── harmonyBle.ts # 与 uni 同名同签名的兼容对象
└── installUniBluetoothPolyfill.ts # 可选:把 uni.* 蓝牙 API 整体接管
5. API 一览
5.1 原生导出 ↔ uni API ↔ 扁平挂载名
| uni 蓝牙 API | 插件导出(utssdk/app-harmony/index.uts) |
形态 B 的 uni 挂载名 | 说明 |
|---|---|---|---|
openBluetoothAdapter |
openAdapter |
harBleCompatOpenAdapter |
内部先申请 ACCESS_BLUETOOTH 再校验蓝牙开关 |
closeBluetoothAdapter |
closeAdapter |
harBleCompatCloseAdapter |
停扫、断开全部连接、清全部监听 |
getBluetoothAdapterState |
getAdapterState |
harBleCompatGetAdapterState |
discovering 为真实扫描态 |
startBluetoothDevicesDiscovery |
startDiscovery |
harBleCompatStartDiscovery |
支持 filters / services / name / namePrefix / allowDuplicatesKey / interval |
stopBluetoothDevicesDiscovery |
stopDiscovery |
harBleCompatStopDiscovery |
— |
onBluetoothDeviceFound |
onDeviceFound |
harBleCompatOnDeviceFound |
支持多注册方并存 |
offBluetoothDeviceFound |
offDeviceFound |
harBleCompatOffDeviceFound |
传引用只移该监听;不传清空全部 |
getBluetoothDevices |
getDiscoveredDevices |
harBleCompatGetDiscoveredDevices |
返回本次扫描会话的快照(原生无独立查询接口) |
createBLEConnection |
createConnection |
harBleCompatCreateConnection |
支持 timeout;只认首个终态 |
closeBLEConnection |
closeConnection |
harBleCompatCloseConnection |
彻底回收 GATT 会话与写队列 |
onBLEConnectionStateChange |
onConnectionStateChange |
harBleCompatOnConnectionStateChange |
事件源为会话级连接监听,断连可感知 |
offBLEConnectionStateChange |
offConnectionStateChange |
harBleCompatOffConnectionStateChange |
— |
getBLEDeviceServices |
getServices |
harBleCompatGetServices |
结果写入内部服务缓存,供读写订阅反查 properties |
getBLEDeviceCharacteristics |
getCharacteristics |
harBleCompatGetCharacteristics |
服务不存在回 10004 |
writeBLECharacteristicValue |
writeCharacteristic |
harBleCompatWriteCharacteristic |
按 properties 自动选 WRITE / WRITE_NO_RESPONSE;同设备写串行 |
readBLECharacteristicValue |
readCharacteristic |
harBleCompatReadCharacteristic |
值同时经 onBLECharacteristicValueChange 派发 |
notifyBLECharacteristicValueChange |
notifyCharacteristic |
harBleCompatNotifyCharacteristic |
CCCD 订阅写走同一条写队列 |
onBLECharacteristicValueChange |
onCharacteristicChange |
harBleCompatOnCharacteristicChange |
支持多注册方并存 |
offBLECharacteristicValueChange |
offCharacteristicChange |
harBleCompatOffCharacteristicChange |
最后一个监听移除时做真原生 off |
setBLEMTU |
setMTU |
harBleCompatSetMTU |
res.mtu 只是请求值(原生不同步回传实际值) |
| —(插件额外) | requestBluetoothPermission |
harBleCompatRequestBluetoothPermission |
单独申请授权;openAdapter 已内嵌,一般无需直接调用 |
5.2 兼容层额外兜底的 uni 成员
harmonyBle 上另外显式挂了这些名字,调用即回 fail(10007)(不是用 Proxy 兜住一切,以保证 typeof obj.xxx === 'function' 的特性探测结果真实):
startBeaconDiscovery、stopBeaconDiscovery、onBeaconUpdate、getBeacons、onBluetoothAdapterStateChange、offBluetoothAdapterStateChange
getSystemInfoSync 委派真 uni(部分 SDK 会用注入对象读 model / brand)。
6. 三种接入形态
形态 A:显式导入 harmonyBle(推荐)
不改动 uni 全局,调用点可静态追踪。非鸿蒙分支用 #ifdef 保持原 uni.* 写法即可。
开发环境(HBuilderX「运行到鸿蒙」)必须同时叠上形态 B 的静态引用钩子:
import { harmonyBle } from '.../ble-api'只引用 JS 层,HBuilderX 不会把本插件的app-harmony/index.uts转译进 har,运行时uni.requireUTSPlugin直接回undefined; 而uni.harBleCompatXxx扁平挂载仅在离线工程手工Reflect.set登记后存在,dev 包恒无。 两条同时为空时openBluetoothAdapter会回fail(10001)。在#ifdef APP-HARMONY块里额外 写一行import * as harBleCompat from '@/uni_modules/har-ble-compat';并调setNativeBridge(harBleCompat as any),就既能触发转译钩子、又能把原生桥注入兼容层。 可直接参考examples/har-ble-demo.vue(形态 A + 形态 B 混用的完整写法)。
形态 B:静态导入原生桥 + setNativeBridge
// #ifdef APP-HARMONY
import * as harBleCompat from '@/uni_modules/har-ble-compat';
import { setNativeBridge } from '@/uni_modules/har-ble-compat/ble-api';
setNativeBridge(harBleCompat as any);
// #endif
桥对象优先级高于扁平挂载。setNativeBridge(null) 可回退。
注入只是「首选来源」。兼容层在每次解析不到函数时会再调一次
uni.requireUTSPlugin('uni_modules/har-ble-compat') 现取(取到才长期缓存),所以原生侧的
registerUTSPlugin 晚于 JS 模块求值、或 dev 包 HMR 重建了 JS 模块,都不会让链路永久不可用;
下一个调用(比如用户点“重新搜索”)就能自愈。
形态 C:全局 polyfill(存量 uni.* 调用点过多时)
import { installUniBluetoothPolyfill } from '@/uni_modules/har-ble-compat/ble-api';
const r = installUniBluetoothPolyfill();
console.log('[ble] 接管', r.installed.length, r.reason);
- 只在原生桥就绪时才覆盖:非鸿蒙端
r.installed为空、uni原实现不受影响。 - 覆盖是整组的:uni 在鸿蒙上「函数存在但空转」,运行时无法区分"可用"与"空转",所以做不到只补缺失项。
uninstallUniBluetoothPolyfill()可还原;重复调用会被拒绝并给出 reason。
7. 注入纯 JS 蓝牙 SDK(本插件的主要使用场景)
很多设备厂商 SDK 是纯 JS、内部只用注入进来的 uni 对象调蓝牙。把 harmonyBle 整体传进去即可复用其协议逻辑,无需把协议移植到原生:
// #ifdef APP-HARMONY
import harmonyBle from '@/uni_modules/har-ble-compat/ble-api';
// 例:SDK 签名为 connect(deviceId, callback, uniLike, timeout)
sdk.createBLEConnection(deviceId, onResult, harmonyBle, 20000);
// #endif
要点:SDK 内部若用 typeof injected.someApi === 'function' 做特性探测,本兼容层的结果是真实的(未实现项是显式函数,不是 Proxy)。
8. 与 uni 的语义差异(迁移前必读)
advertisData已做语义对齐:鸿蒙原生ScanResult.data是整段 raw ADV payload,而 Android/iOS 上uni.advertisData是厂商自定义段(AD type0xFF去掉 length/type 头)。兼容层会抽出0xFF段覆盖advertisData,使"按尾部字节取 MAC"这类上层逻辑保持一致行为;未命中0xFF段时原样返回。advertisServiceUUIDs/serviceData暂不解析:原生不直接给这两个字段,本插件返回空数组。若上层依赖服务 UUID 过滤,请改用filters/services(由原生 ScanFilter 处理)或name/namePrefix。readBLECharacteristicValue双通道给值:原生读取的 Promise 直接带值,兼容层先派发onBLECharacteristicValueChange、再回success,所以「success 里读值」和「监听里读值」两种写法都可用,且只会各收到一次。setBLEMTU不回传实际 MTU:原生setBLEMtuSize是同步 void,res.mtu只是请求值。请以分片行为判断实际 MTU。- ArrayBuffer 跨桥为
Array<number>:ArkTS 的ArrayBuffer经 UTS 桥回 JS 会丢byteLength(序列化成空对象),因此原生 → JS 方向的value/advertisData一律转成Array<number>,由兼容层重建为ArrayBuffer。代价是逐字节拷贝,大数组(>200 字节的高频通知)会有可感知开销。 - *`off` 传引用时的跨桥引用不保证一致:若原生侧匹配不到该引用,只会记一条日志并保留其余监听**(绝不误清空)。需要确定清空时不传参数调用。
- 同一
deviceId的写串行:鸿蒙 GATT 同一时刻只允许一个 pending 写,并发writeCharacteristicValue会被原生拒为The operation is busy。CCCD 订阅写与普通写共用同一队列,单次写超时 5s。 - 建连只认首个终态,但连接监听常驻:
createBLEConnection成功后设备侧断开不会再回头调用那次的fail(避免"幽灵失败"),断连信息只经onBLEConnectionStateChange派发。 - 写入值只接受
ArrayBuffer:ArkTS 不允许在原生侧做运行时形状探测,所以原生实现不再兼容Array<number>/ TypedArray 视图。走harmonyBle或全局 polyfill 的调用方仍可直接传这三种形式,由 JS 侧ensureArrayBuffer()在过桥前统一还原;只有直接调原生导出(形态 A 不经兼容层)时才必须自己保证是ArrayBuffer。
9. 已知限制与待真机核对项
明确不支持:iBeacon 族 API、onBluetoothAdapterStateChange(鸿蒙无对应事件,需轮询 getBluetoothAdapterState)、经典蓝牙、HFP/OPP 等 profile。
已真机核对(3 台真实 BLE 外设——臂式血压计 / 血糖尿酸仪 / 血脂血糖仪,均能连接并同步数据):
扫描起停与设备发现(含会话内去重与 namePrefix 客户端侧过滤)、建连与会话监听、服务/特征发现、notify 订阅(含 CCCD 写)、写特征值、
Array<number> ↔ ArrayBuffer 双向归一化、offBLECharacteristicValueChange 按引用移除。
三台设备合计跑的是同一条链:openBluetoothAdapter → startBluetoothDevicesDiscovery → onBLEDeviceFound → createBLEConnection → getBLEDeviceServices → getBLEDeviceCharacteristics → notifyBLECharacteristicValueChange → writeBLECharacteristicValue → onBLECharacteristicValueChange。
在 HBuilderX dev 包(「运行到鸿蒙」+ 形态 A/B 混用)另行复验通过:openBluetoothAdapter、无过滤起停扫与设备发现、
createBLEConnection、getBLEDeviceServices、getBLEDeviceCharacteristics 均真实回调(单点一台可连外设时回传完整服务/特征列表)。
2026-11-06 就上述链路补测“断开→重连”:对持续广播的外设单击建连→「断开」→再单击同一行重连,getBLEDeviceServices / getBLEDeviceCharacteristics 两次计数逐项一致,证明 closeBLEConnection 后会话回收干净、再次建连无残留。
提醒:演示页的 connect() 带 connecting 重入锁——对同一 deviceId 连点两下会命中插件侧“重复建连先关旧会话”,把刚连上的会话拆掉重连,
紧随的服务发现会撞上拆除窗口而回空;这属调用节奏,非插件缺陷。
已实现但尚未被上述链路覆盖、仍需真机核对(注意:纯 JS 蓝牙 SDK 通常只用 notify 与 write,不用 setBLEMTU / readBLECharacteristicValue / onBLEConnectionStateChange,所以下面这几项不会被业务回归顺带验到):
| 项 | 状态 | 核对要点 |
|---|---|---|
filters / services 生效 |
新增 | 原生 startBLEScan(filters, options) 传数组时的实际过滤效果;16 位短 UUID 是否需补全为 128 位 |
| 无过滤条件起扫 | 已验证 | 传 null(d.ts 明示「不用过滤就置 null」),真机已验证;刻意不传 dutyMode,占空比属未验证行为 |
readBLECharacteristicValue |
新增 | Promise 直接带值 → 派发 change → 回 success 的时序与只读特征实际返回 |
setBLEMTU |
新增 | 系统是否收敛到别的值、大分片是否随之变化 |
onBLEConnectionStateChange |
新增 | 断连事件是否可靠、closeAdapter 后是否残留 |
多监听者 + 按引用 off |
部分已核 | 单注册方的 on/off 已随三台设备回归跑通(业务层每条特征只注册一个监听);多个注册方并存、以及 off 引用不匹配时只记日志不误清,仍只有代码保证,未被真实触发过 |
getDiscoveredDevices |
新增 | 快照范围是否符合上层预期(仅本次扫描会话) |
插件自带 module.json5 权限 |
已核 | 三层均已实测(2026-11-06)。产物层:release 编译中间件 entry/build/.../intermediates/process_profile/default/module.json 的 requestPermissions 含三项蓝牙权限,ACCESS_BLUETOOTH 带 reason: $string:har_ble_bluetooth_reason 与 when: inuse,而宿主 entry/src/main/module.json5 源文件只声明了 INTERNET —— 证明 hvigor 会把插件 HAR(type: har)模块的权限合并进最终模块,使用者不必在宿主侧重复声明。设备层:hdc shell bm dump -n <bundleName> 的安装记录里 moduleName 指向 entry、reasonId 已分配真实值,不是悬空引用。运行时:首次申请的权限弹窗用途文案与插件 string.json 的取值逐字一致(宿主工程内无该文案副本)。仅 DCloud 云端打包本身未实跑,其权限合并走同一套 hvigor 机制 |
上述任一项在你的设备上验证通过后,建议在自己的工程里补一句结论注释,再考虑依赖它。
10. 权限与隐私
本插件自带 utssdk/app-harmony/module.json5,按 DCloud 鸿蒙 UTS 插件机制在编译期拷贝到插件生成的鸿蒙 module,声明:
{
"module": {
"deviceTypes": ["default", "tablet", "2in1"],
"requestPermissions": [
{ "name": "ohos.permission.USE_BLUETOOTH" },
{ "name": "ohos.permission.DISCOVER_BLUETOOTH" },
{
"name": "ohos.permission.ACCESS_BLUETOOTH",
"reason": "$string:har_ble_bluetooth_reason",
"usedScene": { "when": "inuse" }
}
]
}
}
reason 指向插件内 resources/base/element/string.json 的字符串,使用者无需在自己的工程里补。
该合并行为已在 2026-11-06 真机核对:首次 openBluetoothAdapter 弹出的系统授权窗,用途说明即取自本插件的这条字符串(详见第 9 节权限行)。
但离线 / 自定义基座路径仍需手工确认:离线工程走「GUI 出 har + 覆盖原生工程」时,权限实际以宿主的 entry/src/main/module.json5 为准(见第 12 节第 4 步)。
USE_BLUETOOTH/DISCOVER_BLUETOOTH为 system_grant,随安装授予。ACCESS_BLUETOOTH为 user_grant,本插件在openBluetoothAdapter内主动申请(补齐 uni 在鸿蒙缺失的授权弹窗触发时机)。用户拒绝时回fail(10001)。- 部分机型 BLE 扫描还需要
ohos.permission.APPROXIMATELY_LOCATION:插件不强制申请,由调用方按机型需要自行声明与申请。 - 无窗口上下文(应用未进前台 / 后台任务中调用)时,授权申请返回
success(false)并记日志,不会崩溃。 - 数据采集:插件不采集、不上传任何数据;蓝牙广播内容与设备读数全部留在调用方应用内。
11. 错误码
沿用 uni(等同微信小程序)蓝牙码表,不自造新码:
| errCode | 含义 | 本插件的典型触发点 |
|---|---|---|
| 10000 | 未初始化蓝牙适配器 | 未 openBluetoothAdapter 就起扫 |
| 10001 | 蓝牙适配器不可用 | 蓝牙未开、授权被拒、原生桥未接入 |
| 10002 | 没有找到指定设备 | — |
| 10003 | 连接失败 | 建连收到 DISCONNECTED 终态、createBLEConnection 超时、deviceId 非法 |
| 10004 | 没有找到指定服务 | getCharacteristics 的 serviceId 不在设备上 |
| 10005 | 没有找到指定特征 | serviceId / characteristicId 缺失或非法 |
| 10006 | 当前连接已断开 | 未连接状态下调用读写/订阅/MTU |
| 10007 | 特征不支持此操作 | 特征不可写/不可读/不可订阅、未实现 API、mtu 非法 |
| 10008 | 系统异常 | 原生 Promise reject、写超时、起扫/停扫异常 |
| 10009 | 系统蓝牙未授权 | — |
| 10012 | 超过最大连接数 | — |
12. 附录:离线(HBuilderX 使用本地插件)工程集成
DCloud 云端打包会自动处理 UTS 插件。但在离线工程 / 自定义鸿蒙基座下,uni-app 只编译前端静态引用到的 UTS 插件,且原生工程需要一个注册入口。以下五处需手工处理(该形态已在离线工程真机验证):
-
先给前端一个静态引用点(否则第 1 步的 GUI 转译根本不会发生):把插件目录放进
src/uni_modules并不等于它会被转译 —— HBuilderX 是按前端模块图判定是否生成插件 module 的。 若目前还没有真实消费方,加一个只在鸿蒙下生效的引用钩子(一个文件 + 一行#ifdef APP-HARMONY包裹的import):// 引用钩子里只需一次顶层副作用,rollup 才不会把这条 import 摇掉 import * as harBleCompatNative from '@/uni_modules/har-ble-compat'; import { setNativeBridge } from '@/uni_modules/har-ble-compat/ble-api/transport'; setNativeBridge(harBleCompatNative as any);注意两点:①
.uts入口在 npm 侧无类型声明,需给@/uni_modules/har-ble-compat补一句declare module简写声明,否则 tsc 报「找不到模块」; ② 钩子只影响 生成哪几个插件,不影响已产出 har 的内容;har 入位后若不想前端包里多一层未验证的直引式依赖,可把钩子删掉(删后下次重编 har 需再加回)。 -
出 har 包:GUI 生成鸿蒙工程后,构建插件模块的 har。参考脚本思路:
$env:DEVECO_SDK_HOME = 'C:\Program Files\Huawei\DevEco Studio\sdk' $env:JAVA_HOME = 'C:\Program Files\Huawei\DevEco Studio\jbr' node 'C:\Program Files\Huawei\DevEco Studio\tools\hvigor\bin\hvigorw.js' ` --mode module -p product=default -p module=uni_modules__har_ble_compat@default assembleHar --no-daemon模块名以 GUI 实际生成的目录为准(
uni_modules__<插件id>,把-换成_)。 产物固定在<插件目录>\build\default\outputs\default\uni_modules__har_ble_compat.har。.uts → .ets的转译只有 HBuilderX 图形界面的「运行到鸿蒙」会做,cli 命令生成不出原生工程, 所以这一步之前必须先用 GUI 跑一次,再把上面的 hvigor 命令封装成脚本执行(构建前建议先比对 dist 侧 .ets 是否被 GUI 重跑覆盖、并把 har 落位到原生工程 libs\)。 -
在原生工程注册到 uni:编辑
entry/src/main/ets/uni_modules/index.generated.ets,import各导出后Reflect.set挂载:// har-ble-compat HarmonyOS BLE bridge // 必须加 as 别名:若宿主工程另有同名导出的原生蓝牙 UTS 插件(openAdapter / getServices … 重名), // 两个 import 不带别名会在 ArkTS 编译期报重复标识符。 import { openAdapter as compatOpenAdapter, getAdapterState as compatGetAdapterState, // …其余 19 项同理加 compat 前缀别名 } from '@uni_modules/har-ble-compat'; Reflect.set(uni, 'harBleCompatOpenAdapter', compatOpenAdapter); Reflect.set(uni, 'harBleCompatGetAdapterState', compatGetAdapterState); // …按第 5.1 节的名单补齐(共 21 项;未挂的项会自动走可读 fail)扁平名统一用
harBleCompat前缀而不是harBle:宿主工程可能已占用harBleOpenAdapter等名字, 同名挂到 uni 上会互相覆盖,导致兼容层静默绑到旧实现。两套插件共存时互不干扰。必须用
Reflect.set:uni的类型上没有这些名字,直接赋值在 ArkTS 严格模式下会编译失败。实际别名风格以生成脚本为准(
openAdapter as CompatOpenAdapter)。第 2、3 两处登记可用幂等脚本完成 (支持-DryRun先验锚点、追加到既有登记之后、不重排原文件),也可手工编辑这三处。 -
声明扩展 API:
standalone-ext-apis.json增加条目,否则打包校验会报未知 API:{ "plugin": "har-ble-compat", "apis": ["harBleCompatOpenAdapter", "harBleCompatGetAdapterState"], "version": "1.0.0" }apis需与第 2 步实际挂载的名字一一对应。 -
权限声明:按第 10 节写入
entry/src/main/module.json5,并在资源里补bluetooth_reason字符串。
采用「形态 B 扁平挂载 + 纯属性访问」而不是在 JS 里静态
import原生导出,是为了让前端不必把 UTS 模块的引用暴露给非鸿蒙构建;代价就是上面这 4 步手工活。两种形态可共存,桥对象优先级更高。
13. 与朴素 uni 蓝牙垫片的差异
本插件是常见朴素蓝牙垫片的能力超集,但有若干行为差异,迁移时要知情:
| 项 | 朴素垫片常见做法 | 本插件 ble-api |
|---|---|---|
| 原生缺失时的 errCode | 10002 | 10001("桥不在"与"未找到设备"语义区分开) |
getBluetoothDevices |
固定回空数组 | 返回本扫描会话快照 |
readBLECharacteristicValue / setBLEMTU |
显式 notImplemented(10007) |
已实现(见第 9 节,需真机核对) |
| 监听器数量 | 单槽,后注册覆盖前一个 | 多注册方并存,可按引用 off |
filters 入参 |
被忽略(恒传 null) |
生效(新增路径) |
| 未连接时的 errCode | 10007 | 10006(uni 码表中"当前连接已断开"才是 10006) |
本插件是独立发布副本,不改动调用方既有链路。
14. 版本与自检
- 自检:
listMissingApis()返回当前解析不到的原生导出名;isNativeReady()判断桥是否就绪;getTransportMode('openAdapter')告诉你走的是bridge(已注入)、lazy(调用点现取)、flat(扁平挂载)还是none。 - 集成后若所有调用都回
10001,先读errMsg里的现场描述(injected=… / requireUTSPlugin=… / flat=… not found):requireUTSPlugin=cannot且flat=… not found才是第 12 节第 2/3 步没做(har 出了但没挂到 uni);injected=not-injected而requireUTSPlugin=can则只是接线那侧没调setNativeBridge。 - 桥本身正常但目标机没蓝牙射频(鸿蒙模拟器)时,失败来自系统而非本节描述的接线问题;蓝牙验证请用真机。
- 构建要求:HBuilderX 4.61+(
engines已声明),ArkTS 严格模式。
15. 许可
MIT。本插件不包含任何第三方蓝牙 SDK,也不允许随插件再分发;它只是让纯 JS 蓝牙 SDK 能在鸿蒙上跑起来的那层桥。

收藏人数:
下载插件并导入HBuilderX
下载示例项目ZIP
赞赏(0)
下载 49
赞赏 0
下载 12748299
赞赏 1959
赞赏
京公网安备:11010802035340号