更新记录

1.0.1(2026-10-14) 下载此版本

  • 承接项目侧下沉:BLEDeviceBase(含自动重连钩子 / asAutoReconnecting)
  • 导出 toUint8Array:兼容跨 realm BLE 回调缓冲;summarizeBinary 复用

1.0.0(2026-10-14) 下载此版本

  • 首次发布
  • 提供 BLEAdapter、BLEScanCoordinator 及设备发现策略
  • 依赖 pro-device-core

平台兼容性

uni-app(5.06)

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

pro-device-adp-ble — BLE 传输原语

uni_modules BLE 蓝牙传输适配器。提供 BLEAdapter(连接/发送/接收)、BLEScanCoordinator(全局扫描协调器)以及三种设备发现策略。

可独立使用,亦可作为 pro-device 框架的 ITransport 适配器。


架构定位

pro-device-adp-ble
├── BLEAdapter          ← 传输适配器(满足 ITransport 接口)
│   ├── open()          ← 扫描发现 + BLE 建连 + 特征发现 + notify 使能
│   ├── close()         ← 断开 BLE 连接,清理监听器
│   ├── send()          ← 分包写入(MTU 自动协商)
│   ├── onReceive()     ← 订阅 notify 数据
│   └── onDisconnect()  ← 订阅意外断开事件
├── BLEScanCoordinator  ← 进程级单例,解决多设备并发扫描互斥问题
│   ├── scan()          ← 按 matcher 找已知目标
│   └── startDiscovery()← UI 列表发现(与 scan 共用引用计数)
└── 发现策略
    ├── matchByDeviceId    ← 已知 deviceId(默认)
    ├── matchByAdvertisMAC ← 广播包 MAC 反解
    ├── parseAdvertisMAC   ← MAC 解析(UI / matcher 共用)
    └── matchByName        ← 设备广播名称匹配

安装

本插件为项目内置 uni_modules,无需从插件市场安装。

依赖:pro-device-core(仅类型依赖,零运行时依赖)。


核心 API

BLEAdapter — BLE 传输适配器

实现 pro-device 的 ITransport 接口(TypeScript 结构类型系统,无 implements 关键字,满足鸭子类型即可)。

import { BLEAdapter } from '@/uni_modules/pro-device-adp-ble'
import type { BLEAdapterConfig } from '@/uni_modules/pro-device-adp-ble'

配置项 BLEAdapterConfig

interface BLEAdapterConfig {
  /** 设备标识符;语义由 matcher 决定(deviceId / MAC / 名称) */
  ident: string
  /** 设备发现策略,默认 matchByDeviceId */
  matcher?: BLEScanMatcher
  /** 扫描超时时间(ms),默认 10000 */
  scanTimeout?: number
  [key: string]: unknown
}

方法

方法 签名 说明
open(config) Promise<void> 启动蓝牙 → 发现设备 → 建立连接 → 协商 MTU → 发现特征 → 使能 notify
close() Promise<void> 断开 BLE 连接,清理所有监听器
send(data) Promise<void> 将 ArrayBuffer 分包(按协商 MTU)写入可写特征
onReceive(cb) () => void 订阅 notify 特征值变化,返回取消订阅函数
onDisconnect(cb) (reason: TransportDisconnectReason) => void 订阅意外断开(主动 close 不触发),返回取消订阅函数
connected boolean 当前连接状态

直接使用示例

import { BLEAdapter } from '@/uni_modules/pro-device-adp-ble'
import { matchByDeviceId } from '@/uni_modules/pro-device-adp-ble'

const adapter = new BLEAdapter()

await adapter.open({
  ident: 'AA:BB:CC:DD:EE:FF',
  matcher: matchByDeviceId,
  scanTimeout: 10000,
})

const unsub = adapter.onReceive((data) => {
  const bytes = new Uint8Array(data)
  console.log('received:', bytes)
})

await adapter.send(new Uint8Array([0x1b, 0x40]).buffer)

// 清理
unsub()
await adapter.close()

与 pro-device-core 框架配合

import type { ITransport } from '@/uni_modules/pro-device-core'
import { BLEAdapter } from '@/uni_modules/pro-device-adp-ble'

// BLEAdapter 自动满足 ITransport(结构类型),无需 implements
const transport: ITransport = new BLEAdapter()

BLEScanCoordinator — 全局扫描协调器

解决的问题: uni.startBluetoothDevicesDiscovery / stopBluetoothDevicesDiscovery 是小程序平台级全局操作,任意一处调用 stop 会终止所有扫描。当多台设备同时连接时(如打印机 + 电子秤),第一台找到目标后 stop 会强制中止其他设备的扫描。

解决思路:引用计数单例。

第一个消费者加入 → 启动扫描
某消费者找到目标或超时 → 从列表移除
最后一个消费者退出 → 停止扫描

BLEAdapter.open() 内部自动使用协调器,通常无需直接调用。如需自定义发现逻辑:

import { BLEScanCoordinator } from '@/uni_modules/pro-device-adp-ble'
import { matchByName } from '@/uni_modules/pro-device-adp-ble'

const coordinator = BLEScanCoordinator.getInstance()

// 目标匹配:返回 Promise<deviceId>,超时抛出 BLEConnectionError
const deviceId = await coordinator.scan('MY-PRINTER-001', matchByName, 10000)

// 列表发现(与 scan 共用引用计数;仅当订阅与 scan 消费者都为 0 时才 stop)
const unsub = coordinator.startDiscovery({
  onDevices(devices) {
    console.log('nearby', devices)
  },
  onError(err) {
    console.error(err)
  },
})
unsub()

设备发现策略

matchByDeviceId(默认)

适用场景:已知设备的 deviceId(通常为 UUID 格式,在连接历史中缓存)。

import { matchByDeviceId } from '@/uni_modules/pro-device-adp-ble'

// ident 直接作为 deviceId,跳过扫描阶段,直接建连
await adapter.open({ ident: '12345678-1234-1234-1234-1234567890AB', matcher: matchByDeviceId })

注意: 小程序平台 deviceId 格式因平台而异(微信为 UUID,支付宝为 MAC 地址)。matchByDeviceId 跳过了扫描阶段,适合已知设备的快速重连。

matchByAdvertisMAC

适用场景:仅知 MAC 地址时,从广播包末 6 字节反解并进行匹配。

import { matchByAdvertisMAC } from '@/uni_modules/pro-device-adp-ble'

// ident 为设备 MAC 地址(支持 : 或 - 分隔符,大小写不敏感)
await adapter.open({
  ident: 'AA:BB:CC:DD:EE:FF',
  matcher: matchByAdvertisMAC,
  scanTimeout: 10000,
})

matchByName

适用场景:通过设备广播名称匹配(如 Furi DGL-50B、Detonger P1)。

import { matchByName } from '@/uni_modules/pro-device-adp-ble'

await adapter.open({
  ident: 'P1-DEVICE-001',   // 设备广播名称
  matcher: matchByName,
  scanTimeout: 10000,
})

自定义发现策略

import type { BLEScanMatcher } from '@/uni_modules/pro-device-adp-ble'

// 自定义:按厂商数据前缀匹配
const matchByManufacturer: BLEScanMatcher = (devices, ident) => {
  const prefix = ident.toUpperCase()
  for (const d of devices) {
    if (!d.advertisData) continue
    const hex = Array.from(new Uint8Array(d.advertisData as ArrayBuffer))
      .map(b => b.toString(16).padStart(2, '0'))
      .join('')
      .toUpperCase()
    if (hex.startsWith(prefix)) return d.deviceId
  }
  return null  // 返回 null/undefined 表示"继续等待"
}

错误体系

import {
  BLEError,
  BLEConnectionError,
  BLECommunicationError,
} from '@/uni_modules/pro-device-adp-ble'

try {
  await adapter.open(config)
} catch (e) {
  if (e instanceof BLEConnectionError) {
    // 扫描超时、建连失败、设备不在范围内
    console.error('BLE 连接失败', e.message, e.cause)
  } else if (e instanceof BLECommunicationError) {
    // 写特征失败
    console.error('BLE 通信失败', e.message)
  }
}
错误类 触发场景
BLEConnectionError open() 失败(超时/建连失败)、协商 MTU 失败、发现特征失败
BLECommunicationError send() 写特征失败

内部连接流程(open() 详细步骤)

1. openBluetoothAdapter()       — 初始化蓝牙适配器
2. BLEScanCoordinator.scan()   — 扫描(若 matchByDeviceId 则跳过)
3. closeBLEConnection()         — 先断开历史连接(防止状态残留)
4. createBLEConnection()        — 建立 BLE 连接(超时 10s)
5. sleep(500ms)                 — 等待连接稳定
6. setBLEMTU(512)               — 协商 MTU(Android 最大 512,iOS 最大 185)
7. getBLEDeviceServices()       — 获取服务列表
8. getBLEDeviceCharacteristics() — 遍历所有服务,收集可写 + notify 特征
9. notifyBLECharacteristicValueChange() — 使能所有 notify 特征
10. onBLECharacteristicValueChange()    — 注册数据接收监听
11. onBLEConnectionStateChange()        — 注册意外断开监听

平台支持

平台 支持
微信小程序 √
支付宝小程序 √
APP-PLUS(Android / iOS) √
H5 × (小程序 BLE API 不可用)

集成到 pro-device-core 框架

BLE 设备基类已内置于本包:js_sdk/pro-device-adp-ble/ble-device-base.ts(导出 BLEDeviceBase)。 项目机型直接 extends BLEDeviceBase,无需再在 src/devices/base 放一层包装。

隐私、权限声明

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

蓝牙、位置信息(Android BLE 扫描)

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

插件不采集任何数据

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

无

许可协议

MIT协议

暂无用户评论。