更新记录

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)。

本插件做两件事:

  1. 原生补齐:用 @kit.ConnectivityKit 实现蓝牙适配器、扫描、GATT 连接、服务/特征发现、读写、Notify 订阅、连接状态事件、MTU 设置。
  2. 语义零改写兼容:把 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 的语义差异(迁移前必读)

  1. advertisData 已做语义对齐:鸿蒙原生 ScanResult.data 是整段 raw ADV payload,而 Android/iOS 上 uni.advertisData 是厂商自定义段(AD type 0xFF 去掉 length/type 头)。兼容层会抽出 0xFF 段覆盖 advertisData,使"按尾部字节取 MAC"这类上层逻辑保持一致行为;未命中 0xFF 段时原样返回。
  2. advertisServiceUUIDs / serviceData 暂不解析:原生不直接给这两个字段,本插件返回空数组。若上层依赖服务 UUID 过滤,请改用 filters/services(由原生 ScanFilter 处理)或 name/namePrefix。
  3. readBLECharacteristicValue 双通道给值:原生读取的 Promise 直接带值,兼容层先派发 onBLECharacteristicValueChange、再回 success,所以「success 里读值」和「监听里读值」两种写法都可用,且只会各收到一次。
  4. setBLEMTU 不回传实际 MTU:原生 setBLEMtuSize 是同步 void,res.mtu 只是请求值。请以分片行为判断实际 MTU。
  5. ArrayBuffer 跨桥为 Array<number>:ArkTS 的 ArrayBuffer 经 UTS 桥回 JS 会丢 byteLength(序列化成空对象),因此原生 → JS 方向的 value / advertisData 一律转成 Array<number>,由兼容层重建为 ArrayBuffer。代价是逐字节拷贝,大数组(>200 字节的高频通知)会有可感知开销。
  6. *`off` 传引用时的跨桥引用不保证一致:若原生侧匹配不到该引用,只会记一条日志并保留其余监听**(绝不误清空)。需要确定清空时不传参数调用。
  7. 同一 deviceId 的写串行:鸿蒙 GATT 同一时刻只允许一个 pending 写,并发 writeCharacteristicValue 会被原生拒为 The operation is busy。CCCD 订阅写与普通写共用同一队列,单次写超时 5s。
  8. 建连只认首个终态,但连接监听常驻:createBLEConnection 成功后设备侧断开不会再回头调用那次的 fail(避免"幽灵失败"),断连信息只经 onBLEConnectionStateChange 派发。
  9. 写入值只接受 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. 先给前端一个静态引用点(否则第 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 需再加回)。

  2. 出 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\)。

  3. 在原生工程注册到 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 先验锚点、追加到既有登记之后、不重排原文件),也可手工编辑这三处。

  4. 声明扩展 API:standalone-ext-apis.json 增加条目,否则打包校验会报未知 API:

    {
     "plugin": "har-ble-compat",
     "apis": ["harBleCompatOpenAdapter", "harBleCompatGetAdapterState"],
     "version": "1.0.0"
    }

    apis 需与第 2 步实际挂载的名字一一对应。

  5. 权限声明:按第 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 能在鸿蒙上跑起来的那层桥。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

ohos.permission.USE_BLUETOOTH ohos.permission.DISCOVER_BLUETOOTH ohos.permission.ACCESS_BLUETOOTH 用途说明: USE_BLUETOOTH、DISCOVER_BLUETOOTH:系统授权(system_grant),随安装授予,用于开关蓝牙适配器与扫描/发现 BLE 外设。 ACCESS_BLUETOOTH:用户授权(user_grant),在调用 openBluetoothAdapter 时主动申请,用于 GATT 连接、服务/特征发现与读写、Notify 订阅。 说明:部分机型 BLE 扫描还需定位权限(ohos.permission.APPROXIMATELY_LOCATION),本插件不声明、不强制,由调用方按需在宿主工程申请——所以它不属于「本插件申请的权限」,不要写进上面列表,否则与 module.json5 不符会被打回。

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据。 说明:本插件仅为 uni-app 蓝牙 API 在 HarmonyOS 上的原生兼容桥,不发起任何网络请求、不上传或存储任何数据;蓝牙扫描到的广播内容、外设名称/标识(deviceId)、特征值读写等全部留在调用方应用进程内,由调用方自行处理。插件不包含任何第三方蓝牙 SDK。

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

无

许可协议

MIT协议

暂无用户评论。