更新记录

1.0.0(2026-09-18) 下载此版本

首个正式版本

  • 四端支持:Android 5.0+(API 21)/ iOS 12.0+ / HarmonyOS NEXT(API 12)/ 微信小程序(基础库 2.9.2+);uni-app(vue2/vue3)与 uni-app x 双框架
  • 中心设备能力:BLE 扫描(服务UUID/名称前缀过滤、功耗等级、去重上报)、多设备并发连接、服务/特征发现、读写(带/无响应自动选择)、通知订阅(自动写 CCCD)、setBLEMTU
  • 状态监听:蓝牙开关、扫描状态、连接状态变化,统一 on/off 事件对
  • 外围能力:BLE 广播 + GATT Server(安卓/iOS/鸿蒙;微信小程序受平台限制返回 9020003)
  • GBK 全量(cp936)编解码内置:encodeGBK/decodeGBK、字符串收发 API(GBK/UTF-8/HEX)、autoSplit 自动分包;四端编解码逐字节一致(全量回归验证)
  • Android 体验:按应用 targetSdk 自适应申请权限、蓝牙未开自动拉起系统开启授权弹窗、SCAN_RSP 设备名自动补报
  • 工程细节:每设备串行写队列、valueHex 入参规避 Android uni-app ArrayBuffer 限制、遵循 uni 错误码规范(902xxxx)
  • 附 uni-app / uni-app x 双演示工程(设备列表页 + 收发信息页,含广播回显测试)

平台兼容性

uni-app(4.51)

Vue2 Vue2插件版本 Vue3 Vue3插件版本 Chrome Safari app-vue app-vue插件版本 app-nvue app-nvue插件版本 Android iOS 鸿蒙
1.0.0 1.0.0 - - 1.0.0 1.0.0 - - -
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
- - - - - - - -

uni-app x(4.61)

Chrome Safari Android Android插件版本 iOS iOS插件版本 鸿蒙 鸿蒙插件版本 微信小程序 微信小程序插件版本
× × 5.0 1.0.0 12 1.0.0 12+ 1.0.0 2.9.2 1.0.0

其他

多语言 暗黑模式 宽屏模式
× ×

xm-uts-ble 蓝牙 BLE 插件

UTS 编写的跨端蓝牙 BLE 插件:安卓 / iOS / 鸿蒙Next / 微信小程序 一套 API。

支持平台:App-Android 5.0+ | App-iOS 12.0+ | HarmonyOS NEXT(API 12) | 微信小程序 | uni-app + uni-app x | 免费开源(MIT)

<!-- 效果展示:截图补齐后取消本段注释 ![初始化](screenshot/1-init.png) ![扫描列表](screenshot/2-scan.png) ![GBK收发](screenshot/3-chat-gbk.png) ![HEX与通知](screenshot/4-hex.png) ![广播回显](screenshot/5-server.png) -->
能力 说明 app-android app-ios app-harmony mp-weixin
蓝牙扫描 支持服务UUID/名称前缀过滤、功耗等级、重复上报
蓝牙状态监听 蓝牙开关、扫描状态变化
多设备连接 deviceId 上下文隔离、连接状态监听
数据读写 读/写(带·无响应)/通知订阅/MTU
GBK 编码 内置全量 cp936 表,中文设备直连
BLE 广播 可连接/不可连接广播、厂商数据 ❌ 微信平台限制
GATT Server 被连接、读写事件回调、通知回包 ❌ 微信平台限制

API 命名与微信小程序 / uni 蓝牙 API 对齐(openBluetoothAdaptercreateBLEConnection…),微信蓝牙业务可近乎零成本迁移。

功能特性

  • 多蓝牙设备同时连接,每设备独立串行写队列(BLE 写必须串行,队列自动泵送)
  • GBK / UTF-8 / HEX 三编码收发:writeBLECharacteristicString 直接发中文、onBLECharacteristicString 直接收到解码后的字符串
  • 全量 GBK(cp936) 编解码为纯 UTS 实现(23940 双字节条目),四端解码/编码结果逐字节一致(工具链含全量回归测试)
  • 蓝牙适配器开关监听、连接断开监听、扫描状态统一走 onXXX/offXXX 事件对
  • 分包工具 splitBuffer + autoSplit 一键大包拆包发送
  • valueHex 十六进制入参:规避 Android uni-app(vue) 下 ArrayBuffer 不能作插件入参的系统限制
  • 遵循 uni 错误码规范(9020xxx),BleFail.errCode/errMsg/errSubject

平台要求

  • HBuilderX 4.61+(uni-app x 与鸿蒙平台;uni-app 工程最低 4.51+,iOS ArrayBuffer 插件转换 API 要求)
  • Android 5.0+(API 21);iOS 12.0+;HarmonyOS NEXT(API 12);微信基础库 2.9.2+

安装

在 HBuilderX 中打开 插件市场 搜索 xm-uts-ble,或从本仓库复制 uni_modules/xm-uts-ble 到项目 uni_modules 目录。

权限配置

Android

插件已内置 AndroidManifest.xml,云打包自动合并(新旧两套权限同时声明,不设 maxSdkVersion,避免 targetSdk<31 的应用在 Android 12+ 设备上旧权限被剥离):

  • BLUETOOTH / BLUETOOTH_ADMIN / ACCESS_FINE_LOCATION / ACCESS_COARSE_LOCATION
  • BLUETOOTH_SCAN(neverForLocation) / BLUETOOTH_CONNECT

运行时权限由 openBluetoothAdapter() 自动拉起申请(可传 requestPermissions: false 关闭),按应用 targetSdkVersion 自动二选一:target≥31 申请新权限;target<31 申请定位权限(低 target 申请 BLUETOOTH_CONNECT 会被系统抛 IllegalStateException,已规避)。

iOS

插件已内置 Info.plist(合并到工程):NSBluetoothAlwaysUsageDescription、后台模式 bluetooth-central / bluetooth-peripheral(不需要后台 BLE 可自行删除)。

鸿蒙

在项目的 harmony-configs(或 HBuilderX 鸿蒙工程配置)module.json5 中为 Entry 添加:

"requestPermissions": [
  { "name": "ohos.permission.ACCESS_BLUETOOTH",
    "reason": "$string:ble_reason", "usedScene": { "when": "inuse" } },
  { "name": "ohos.permission.APPROXIMATELY_LOCATION",
    "reason": "$string:loc_reason", "usedScene": { "when": "inuse" } }
]

微信小程序

  • 隐私协议(必须):蓝牙 API 属微信隐私接口,未声明会报 api scope is not declared in the privacy agreement(插件映射为 9020002)。处理:
    1. 正式发布:微信公众平台 → 设置 → 服务内容声明 → 用户隐私保护指引 → 添加“蓝牙”收集使用声明,通过后生效(用户需同意隐私弹窗,可用 wx.requirePrivacyAuthorize/官方隐私弹窗组件)
    2. 本地调试:微信开发者工具 → 详情 → 本地设置 → 勾选 不校验隐私接口(不同版本工具措辞略有差异)
  • 手机端需开启蓝牙与定位(iOS 微信扫描依赖系统定位服务)
  • 小程序不支持蓝牙广播/GATT Server(调用相应 API 返回 9020003

快速开始

import {
  openBluetoothAdapter, startBluetoothDevicesDiscovery, onBluetoothDeviceFound,
  createBLEConnection, getBLEDeviceServices, notifyBLECharacteristicValue,
  writeBLECharacteristicString, onBLECharacteristicString, setBLEMTU
} from '@/uni_modules/xm-uts-ble'

// 1. 初始化(自动申请权限)
openBluetoothAdapter({
  success: () => {
    // 2. 设备发现
    onBluetoothDeviceFound(res => {
      res.devices.forEach(d => console.log(d.name, d.deviceId, d.RSSI))
    })
    startBluetoothDevicesDiscovery({
      services: ['180D'],        // 可选:按服务UUID过滤(支持16bit简写)
      allowDuplicatesKey: false,
      powerLevel: 'high'
    })

    // 3. 连接(支持同时连接多台设备,按 deviceId 区分)
    createBLEConnection({
      deviceId: 'AA:BB:CC:DD:EE:FF',
      timeout: 10000,
      success: () => {
        setBLEMTU({ deviceId: 'AA:BB:CC:DD:EE:FF', mtu: 247 })
        getBLEDeviceServices({
          deviceId: 'AA:BB:CC:DD:EE:FF',
          withCharacteristics: true,   // 一次取回服务+特征
          success: res => console.log(JSON.stringify(res.services))
        })
      }
    })

    // 4. GBK 中文收发
    onBLECharacteristicString(res => {
      console.log('收到:', res.value, res.hex)   // value 已按 GBK 解码
    }, 'gbk')
    writeBLECharacteristicString({
      deviceId: 'AA:BB:CC:DD:EE:FF',
      serviceId: 'fff0',
      characteristicId: 'fff1',
      value: '温度查询',           // 中文 → GBK 字节
      encoding: 'gbk',
      autoSplit: true,            // 大包自动拆分(默认20字节/包)
      chunkSize: 20
    })
  },
  fail: err => console.log(err.errCode, err.errMsg)
})

uni-app(vue) 下发送 hex 数据(Android ArrayBuffer 限制规避)

writeBLECharacteristicValue({
  deviceId, serviceId, characteristicId,
  value: null,
  valueHex: 'a1b2c3d4',   // 十六进制字符串
  success: () => {}, fail: e => {}
})

蓝牙广播 + GATT Server(App 三端)

import {
  startGattServer, startBLEAdvertising, onGattServerWriteRequest,
  sendGattServerNotification
} from '@/uni_modules/xm-uts-ble'

// 定义一个被连接的服务(示例: Nordic UART 风格回显)
startGattServer({
  services: [{
    uuid: '6e400001-b5a3-f393-e0a9-e50e24dcca9e',
    characteristics: [
      { uuid: '6e400002-b5a3-f393-e0a9-e50e24dcca9e', properties: ['write'], permissions: ['write'] },
      { uuid: '6e400003-b5a3-f393-e0a9-e50e24dcca9e', properties: ['notify', 'read'], permissions: ['read'] }
    ]
  }]
})

// 收到对端写入 → 回显通知
onGattServerWriteRequest(req => {
  sendGattServerNotification({
    deviceId: req.deviceId,
    serviceId: '6e400001-b5a3-f393-e0a9-e50e24dcca9e',
    characteristicId: '6e400003-b5a3-f393-e0a9-e50e24dcca9e',
    value: req.value
  })
})

startBLEAdvertising({
  serviceUUIDs: ['6e400001-b5a3-f393-e0a9-e50e24dcca9e'],
  includeDeviceName: true,
  manufacturerData: hexToBuffer('8801584D'),   // 前2字节为公司ID(小端)
  connectable: true
})

API 一览

适配器

API 说明
openBluetoothAdapter(options?) 初始化,自动申请权限;蓝牙未开启返回 9020001
closeBluetoothAdapter(options?) 关闭并释放全部资源(扫描/连接/广播/Server)
getBluetoothAdapterState(options) {available, discovering}
onBluetoothAdapterStateChange(cb) / off... 蓝牙开关与扫描状态变化

扫描

API 说明
startBluetoothDevicesDiscovery(options) services/namePrefix/allowDuplicatesKey/interval/powerLevel
stopBluetoothDevicesDiscovery(options?) 停止扫描
onBluetoothDeviceFound(cb) / off... 设备发现事件,res.devices[]deviceId/name/localName/RSSI/connectable/serviceUUIDs/advertisData/raw
getBluetoothDevices(options) 已发现设备缓存
getConnectedBluetoothDevices(options) 已连接设备(按 services 过滤)

连接与收发

API 说明
createBLEConnection({deviceId, timeout?}) 连接,支持多设备并发连接
closeBLEConnection({deviceId}) 断开
onBLEConnectionStateChange(cb) / off... 连接状态监听 {deviceId, connected}
getBLEDeviceServices({deviceId, withCharacteristics?}) 服务列表;withCharacteristics:true 时一并拉取特征
getBLEDeviceCharacteristics({deviceId, serviceId}) 特征列表(read/write/writeNoResponse/notify/indicate)
writeBLECharacteristicValue({deviceId, serviceId, characteristicId, value 或 valueHex, type?}) 写(带/无响应自动选择,超长返回 9020015)
writeBLECharacteristicString({value, encoding='gbk', autoSplit?, chunkSize?, splitInterval?}) 字符串编码发送,可自动分包
readBLECharacteristicValue({...}) 读(结果统一从 onBLECharacteristicValueChange 返回)
notifyBLECharacteristicValue({state=true}) 订阅/取消通知(自动写 CCCD)
onBLECharacteristicValueChange(cb) / off... 原始字节回调 value: ArrayBuffer
onBLECharacteristicString(cb, encoding='gbk') / off... 字符串回调 {value, hex}
setBLEMTU({deviceId, mtu}) Android 请求 MTU;iOS 返回系统协商值;鸿蒙 setBLEMtuSize

广播 / GATT Server(App 三端;微信小程序返回 9020003)

API 说明
startBLEAdvertising({serviceUUIDs?, manufacturerData?, includeDeviceName?, connectable?, scanResponseData?}) 开始广播
stopBLEAdvertising(options?) 停止
onBLEAdvertisingStateChange(cb) / off... {isAdvertising}
startGattServer({services}) 启动 GATT Server 并注册服务;ServerCharacteristicDef{uuid, properties[], permissions[], value?}
stopGattServer(options?) 停止并释放
onGattServerReadRequest(cb) / off... 对端读请求;注册回调后需业务调用 sendGattServerResponse 回包;未注册时插件自动以内置值回包
onGattServerWriteRequest(cb) / off... 对端写请求;注册回调后需 sendGattServerResponse 确认(未注册自动 ACK)
sendGattServerResponse({deviceId, requestId, status?, value?}) 回包/ACK,requestId 透传自回调
sendGattServerNotification({deviceId, serviceId, characteristicId, value 或 valueHex, indicate?}) 向指定中心设备推送
onGattServerConnectionStateChange(cb) / off... 对端连接/断开、MTU(iOS 不触发,安卓/鸿蒙支持)

工具(全平台可用,纯 UTS 实现)

encodeGBK(str): ArrayBufferdecodeGBK(buf): stringencodeUtf8decodeUtf8bufferToHexhexToBuffersplitBuffer(buf, size)expandUuiduuidEqualsbytesToBufferbufferToBytes

错误码

errCode 含义
9020001 蓝牙不可用/未开启
9020002 权限被拒绝 / 小程序隐私协议未声明蓝牙
9020003 当前平台不支持(如小程序广播)
9020004 适配器未初始化
9020005 扫描启动失败
9020006 设备未找到
9020007 连接失败/超时
9020008 设备未连接
9020009 服务未找到
9020010 特征未找到
9020011 读失败
9020012 写失败
9020013 设置通知失败
9020014 设置MTU失败
9020015 数据超过当前MTU
9020016 广播启动失败
9020017 设备不支持BLE广播
9020018 GATT Server 启动失败
9020019 参数错误
9020099 未知错误

平台差异与注意事项

  1. iOS deviceId 为系统 UUID(非 MAC),且只能连接“本进程扫描到过的”设备(与微信一致)。
  2. Android uni-app(vue):ArrayBuffer 不能作为插件入参 → 写数据用 valueHex 或字符串接口;插件返回值/回调中的 ArrayBuffer 正常可用。
  3. 广播能力检测:安卓部分机型不支持外围广播(isMultipleAdvertisementSupported=false 返回 9020017);iOS 广播需真机。
  4. interval/allowDuplicatesKey 在部分平台为近似实现(按设备去重上报);去重模式下,若首次上报无名称、后续 SCAN_RSP 带出名称,插件会自动补报一次该设备(UI 按 deviceId 覆盖即可显示名称)。
  5. offXXX(callback) 按函数引用移除:请保存回调引用;不传参移除该事件全部监听。
  6. 断开设备后请调用 closeBLEConnectioncloseBluetoothAdapter 会释放全部连接/广播/Server。
  7. 读特征成功回调仅代表“读指令已下发”,数据一律从 onBLECharacteristicValueChange/String 返回(微信同款行为)。
  8. 鸿蒙端 API 以本机 SDK 为准,若编译报签名差异请按文末“编译核对清单”微调。

iOS 测试与编译核对清单

前置条件(二选一)

  • 路线 A(免费):借一台 Mac + 免费 Apple ID。Mac 装 HBuilderX,工程拷入后直接「运行 → 运行到 iOS App」真机调试(Xcode 自动签名,7 天有效)。UTS→Swift 编译错误在 HBuilderX 控制台即时可见,是修错最快的方式。
  • 路线 B(付费 $99/年):Apple 开发者账号 + Windows 云打包。developer.apple.com 注册设备 UDID(爱思助手可读取)→ 创建开发证书(.p12,CSR 可用 openssl 生成)与描述文件(.mobileprovision) → HBuilderX 云打包 iOS 填自有证书;或在打包弹窗用 Apple ID 托管自动建证书。产物 ipa 用爱思助手安装。

首次 iOS 编译可能需微调的灰度点(已按文档证据择优实现)

  1. CBATTError.Code(rawValue = x)!(可失败枚举初始化写法)
  2. UTS 函数引用比较 ===(offXXX 回调身份匹配,Swift 闭包不支持 ==
  3. Swift 数组 ↔ UTS Array 透明桥接(peripheral.services 赋值)
  4. Map<string, any> → Swift [String: Any](广播参数、handleAdv 解析)
  5. catch (e : Exception)e.message(iOS 侧 UTSError 属性)
  6. delegate 方法 @argumentLabel 与本机 SDK 签名核对(didDiscover/didUpdateValueFor/respond 等)

iOS 平台行为差异(非 bug)

  • 只能连接本会话扫描到过的设备(否则 9020006),与微信一致
  • deviceId 为系统 UUID;setBLEMTU 不支持主动设置,返回系统协商值
  • onGattServerConnectionStateChange iOS 无对等 API,不触发(安卓/鸿蒙支持)
  • 广播/被连仅真机可用;蓝牙需用户在系统设置手动开启(iOS 禁止代码开启)

其他平台编译核对清单

  • Android:已通过云打包编译验证(v0.1.0 迭代修复记录见 changelog)
  • 鸿蒙:connectionManager.startAdvertising/BLEAdvertisingSettingregisterServerCallback/ServerCallbackGattCharacteristic.writeType(WRITE_VALUE=带响应 / WRITE_COMMAND=无响应) 以本机 SDK d.ts 为准
  • 真机验证顺序建议:小程序(纯转发最稳) → 安卓 → iOS → 鸿蒙

仓库结构

ble-plugin/
├─ uni_modules/xm-uts-ble/        # 插件本体(单一真源)
│  ├─ package.json / readme.md / changelog.md
│  └─ utssdk/
│     ├─ interface.uts             # 全部类型与API声明
│     ├─ unierror.uts              # 错误码实现
│     ├─ common/                   # 跨端共享:事件中心/GBK/UTF8/hex/分包/写队列
│     ├─ app-android/  index.uts + AndroidManifest.xml + config.json
│     ├─ app-ios/      index.uts + Info.plist + config.json
│     ├─ app-harmony/  index.uts
│     ├─ mp-weixin/    index.uts
│     └─ web/          index.uts    # 占位,返回9020003
├─ apps/
│  ├─ demo-uniappx/                # uni-app x 演示(安卓/iOS/鸿蒙真机)
│  └─ demo-uniapp/                 # uni-app vue3 演示(微信小程序+App)
└─ tools/
   ├─ gen-gbk-table.mjs            # 从 iconv-lite cp936 生成内置映射表
   └─ test-gbk.mjs                 # GBK 全量回归(对照 iconv 逐字节校验)

apps/*uni_modules/xm-uts-ble 为目录联接(junction),指向插件本体,修改即时同步。

测试

cd tools && npm i && node gen-gbk-table.mjs && node test-gbk.mjs && node check-syntax.mjs
  • test-gbk.mjs:GBK 全量回归(当前 23940/23940 解码一致、21791 编码可逆、round-trip 通过)
  • check-syntax.mjs:esbuild 对所有 .uts/demo 脚本做语法变换检查(与 vite:esbuild 同解析器;iOS 文件会先屏蔽 @argumentLabel、Swift 标签等 UTS 专有语法再校验)

License

MIT

隐私、权限声明

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

蓝牙扫描/连接权限(Android 12+ 为 BLUETOOTH_SCAN/BLUETOOTH_CONNECT,11 及以下为定位权限,用于 BLE 扫描);iOS 蓝牙授权弹窗(NSBluetoothAlwaysUsageDescription)

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

插件不采集任何数据,蓝牙通信数据仅在应用本地处理,不上传任何服务器

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

许可协议

MIT协议

暂无用户评论。