更新记录

1.0.0(2026-11-05)

  • 首个版本:支持 uni-app 与 uni-app x(Android)。
  • SDK 生命周期:init / isInitialized / release / destroy / setDebugMode。
  • 适配器:getBluetoothAdapter / isBluetoothOn / getPairedDevices。
  • 搜索与配对:startDiscovery / stopDiscovery / isDiscovering / getBondState / createBond / removeBond / clearBondDevices。
  • 多连接管理:createConnection / connect / disconnectConnection / disconnectAllConnections / releaseConnection / releaseAllConnections / getConnection / getConnections / getOrderedConnections / getFirstConnection / getLastConnection / clearQueue。
  • 数据写入:write(hex / base64 / text 三选一,支持 tag 回执、immediate 插队、viaObserver 事件回执)。
  • 事件观察者:registerObserver / unregisterObserver / isObserverRegistered,事件涵盖蓝牙开关、搜索、配对、连接状态与数据收发。
  • 配对状态事件 onBondStateChanged:createBond / removeBond / clearBondDevices 以及系统设置里的配对变化都会推送 10 / 11 / 12,不依赖连接对象是否存在。
  • 运行时权限:requestPermissions / checkPermissions,提供逐项授予状态与永久拒绝列表。
  • 连接超时保护:connect 默认 12 秒超时,超时主动断开并返回 9270019。

平台兼容性

uni-app(4.72)

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

uni-app x(4.72)

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

zy-classic-bluetooth

插件介绍

安卓经典蓝牙(Bluetooth Classic / SPP)UTS 原生插件,支持 uni-app 与 uni-app x(仅 Android)。提供多设备并发连接、自定义服务 UUID、写入队列与 tag 回执、搜索配对、连接状态机与双向数据收发能力,可直接与蓝牙串口模块、单片机、传感器、打印机等设备通信。

使用场景

  • 一台手机同时连接多台经典蓝牙串口设备,并行收发互不干扰。
  • 工业设备「一问一答」通信:每次写入带 tag,用回执里的 tag 与耗时对应请求与响应。
  • 设备使用非标准 SPP 服务 UUID 的透传通道,需要在连接时指定自定义 UUID。
  • 需要在界面上区分「配对中 / 已配对 / 已连接 / 已释放」等精细状态的设备管理页。

使用流程

  1. 调用 requestPermissions 申请扫描、连接、定位权限(Android 12 及以上也需定位权限,见「权限说明」)。
  2. 调用 init 初始化,onEvent 中接收蓝牙开关、搜索、配对、连接、数据等全部事件。
  3. 用 getPairedDevices 取已配对设备,或 startDiscovery 搜索新设备(结果走 onDeviceFound 事件)。
  4. 需要时用 createBond 发起配对,配对过程与结果通过 onBondStateChanged 事件观察(11 配对中 / 12 已配对),也可用 getBondState 主动查询。
  5. 调用 createConnection 创建连接实例(可选),再调用 connect 发起连接;success 在真正连接成功时回调。
  6. 用 write 发送数据,通过回调或 onWrite 事件拿到写入结果。
  7. 用 disconnectConnection 断开(可重连)或 releaseConnection 释放(需重新创建)。
  8. 页面卸载时调用 destroy 释放全部资源。

用法

import {
    init,
    destroy,
    requestPermissions,
    checkPermissions,
    getBluetoothAdapter,
    isBluetoothOn,
    getPairedDevices,
    startDiscovery,
    stopDiscovery,
    isDiscovering,
    createConnection,
    connect,
    disconnectConnection,
    disconnectAllConnections,
    releaseConnection,
    releaseAllConnections,
    getConnection,
    getConnections,
    getOrderedConnections,
    getFirstConnection,
    getLastConnection,
    clearQueue,
    write,
    getBondState,
    createBond,
    removeBond,
    clearBondDevices
} from '@/uni_modules/zy-classic-bluetooth'

权限

requestPermissions({
    success: (res) => {
        // res.allGranted 是否全部授予
        // res.list 每项 { name, granted }
        // res.permanentlyDenied 被永久拒绝的权限(需引导用户到系统设置手动开启)
        console.log('权限结果', res)
    },
    fail: (err) => console.error(err.errCode, err.errMsg)
})

// 只检查不弹框
checkPermissions({
    success: (res) => console.log(res.allGranted)
})

初始化与事件

init({
    debug: false, // 是否输出底层调试日志,默认 false
    threadMode: 'main', // 事件与回调线程:main / posting / background / async
    onEvent: (event) => {
        switch (event.type) {
            case 'onBluetoothAdapterStateChanged':
                console.log('蓝牙开关状态', event.adapterState) // 10 关闭 / 11 正在开启 / 12 已开启 / 13 正在关闭
                break
            case 'onDeviceFound':
                console.log('发现设备', event.name, event.address, event.rssi, event.bondState)
                break
            case 'onDiscoveryStart':
            case 'onDiscoveryStop':
                console.log('搜索状态变化', event.type)
                break
            case 'onDiscoveryError':
                console.log('搜索错误', event.discoveryErrorCode, event.message) // 0~4
                break
            case 'onBondStateChanged':
                // 配对状态:10 未配对 / 11 配对中 / 12 已配对(createBond / removeBond / 系统设置变化都触发)
                console.log('配对状态', event.address, event.bondState)
                break
            case 'onConnectionStateChanged':
                // 0 未连接 / 1 连接中 / 2 配对中 / 3 已配对 / 4 已连接 / 5 已释放
                console.log('连接状态', event.address, event.uuid, event.state)
                break
            case 'onRead':
                console.log('收到数据', event.hex, event.text, event.length)
                break
            case 'onWrite':
                // 仅 write 传 viaObserver: true 时下发
                console.log('写入结果', event.tag, event.success)
                break
        }
    },
    success: () => console.log('初始化完成'),
    fail: (err) => console.error(err.errCode, err.errMsg)
})

搜索与配对

getPairedDevices({
    success: (res) => console.log('已配对', res.list) // [{ name, address, bondState, type, rssi }]
})

startDiscovery({
    success: () => console.log('已发起搜索'),
    fail: (err) => console.error(err.errCode, err.errMsg) // 9270004 蓝牙未开启 / 9270005 缺扫描权限 / 9270007 缺定位权限
})

stopDiscovery({ success: () => console.log('已停止搜索') })

createBond({
    address: '00:11:22:33:44:55',
    success: () => console.log('配对请求已发起')
})

getBondState({
    address: '00:11:22:33:44:55',
    success: (res) => console.log('配对状态', res.bondState) // 10 / 11 / 12
})

removeBond({
    address: '00:11:22:33:44:55',
    success: () => console.log('已请求解除配对')
})

连接

// 连接(不传 uuid 时使用默认 SPP UUID 00001101-0000-1000-8000-00805f9b34fb)
connect({
    address: '00:11:22:33:44:55',
    uuid: '00001101-0000-1000-8000-00805f9b34fb', // 可选,自定义服务 UUID
    timeout: 12000, // 可选,连接超时毫秒,默认 12000,超时回 9270019
    success: (conn) => {
        // conn: { address, name, uuid, state, connected, released, bondState }
        console.log('已连接', conn)
    },
    fail: (err) => console.error(err.errCode, err.errMsg)
})

// 只创建连接实例,不发起连接
createConnection({ address: '00:11:22:33:44:55' })

// 查询
getConnections({ success: (res) => console.log('全部连接', res.list) })
getOrderedConnections({ success: (res) => console.log('按创建顺序', res.list) })
getFirstConnection({ success: (conn) => console.log(conn) })
getLastConnection({ success: (conn) => console.log(conn) })
getConnection({ address: '00:11:22:33:44:55', success: (conn) => console.log(conn.state) })

// 断开(可重连)
disconnectConnection({ address: '00:11:22:33:44:55' })
disconnectAllConnections()

// 释放(不可重连,需要重新创建)
releaseConnection({ address: '00:11:22:33:44:55' })
releaseAllConnections()

数据收发

// 文本(UTF-8)
write({
    tag: 'req1', // 写入标识,回执中原样返回
    text: 'hello',
    success: (res) => console.log('写入成功', res.tag, res.length, res.cost + 'ms')
})

// 十六进制(空格、逗号、短横线、冒号、0x 前缀会被忽略)
write({
    address: '00:11:22:33:44:55', // 多连接时指定目标,省略时使用第一个连接
    tag: 'req2',
    hex: '01 02 FF',
    immediate: true // 插入队首优先发送
})

// base64
write({ tag: 'req3', base64: 'AQIDBA==' })

// 写入结果走事件(不传回调时可用于统一日志)
write({ tag: 'req4', hex: 'AA BB', viaObserver: true })

// 清空待发送队列
clearQueue({ address: '00:11:22:33:44:55' })

释放

destroy({ success: () => console.log('已销毁,可重新 init') })

插件方法

方法 说明 回调
init(options) 初始化,注册事件观察者与系统蓝牙广播监听 success / onEvent(持续) / fail
isInitialized(options) 是否已初始化 success:{ value }
release(options) 释放 SDK(断开全部连接、注销监听),可再次 init success
destroy(options) 销毁 SDK 实例,可重新 init 并按新配置构建 success
setDebugMode(options) 开关底层调试日志 success:{ value }
requestPermissions(options) 申请运行时权限(缺省:扫描 / 连接 / 定位) success:ClassicPermissionResult
checkPermissions(options) 检查权限(不弹框) success:ClassicPermissionResult
getBluetoothAdapter(options) 本机蓝牙适配器快照 success:{ name, address, state, enabled, discovering }
isBluetoothOn(options) 蓝牙是否已开启 success:{ value }
getPairedDevices(options) 系统已配对设备列表 success:{ list }
startDiscovery(options) 开始搜索,结果走 onDeviceFound 事件 success / fail
stopDiscovery(options) 停止搜索 success
isDiscovering(options) 是否正在搜索 success:{ value }
registerObserver(options) 重新注册事件观察者(init 时已自动注册) success
unregisterObserver(options) 取消事件观察者(连接与数据仍在底层运行) success
isObserverRegistered(options) 观察者是否已注册 success:{ value }
createConnection(options) 创建连接实例(不发起连接) success:ClassicConnection
connect(options) 发起连接,成功后才回调 success success:ClassicConnection / fail
disconnectConnection(options) 断开指定连接(可重连) success
disconnectAllConnections(options) 断开全部连接 success
releaseConnection(options) 释放指定连接(不可重连) success
releaseAllConnections(options) 释放全部连接 success
getConnection(options) 查询指定连接 success:ClassicConnection
getConnections(options) 全部连接(无序) success:{ list }
getOrderedConnections(options) 全部连接(按创建顺序) success:{ list }
getFirstConnection(options) 第一个创建的连接 success:ClassicConnection
getLastConnection(options) 最后一个创建的连接 success:ClassicConnection
clearQueue(options) 清空指定连接的待写队列 success
write(options) 写入数据(hex / base64 / text 三选一) success:ClassicWriteResult / onWrite(viaObserver)
getBondState(options) 查询配对状态 success:{ address, bondState }
createBond(options) 发起配对 success / fail,配对结果走 onBondStateChanged 事件
removeBond(options) 解除配对 success / fail,解除结果走 onBondStateChanged 事件
clearBondDevices(options) 批量解除配对(不传 addresses 表示全部) success / fail,结果走 onBondStateChanged 事件

连接对象(ClassicConnection)

{
    address: '00:11:22:33:44:55', // 设备 MAC
    name: 'HC-05',                // 设备名称,无权限时为空字符串
    uuid: '00001101-...',         // 该连接使用的服务 UUID
    state: 4,                     // 0 未连接 | 1 连接中 | 2 配对中 | 3 已配对 | 4 已连接 | 5 已释放
    connected: true,              // 是否已连接(state == 4)
    released: false,              // 是否已释放(released 后不可重连)
    bondState: 12                 // 配对状态:10 未配对 | 11 配对中 | 12 已配对
}

事件对象(ClassicEvent)

所有字段始终存在,不属于当前事件的字段为空字符串 / 0 / false。

{
    type: 'onRead',        // onBluetoothAdapterStateChanged | onRead | onWrite | onConnectionStateChanged |
                           // onBondStateChanged | onDiscoveryStart | onDiscoveryStop | onDeviceFound | onDiscoveryError
    address: '00:11:...',  // 设备 MAC
    name: 'HC-05',         // 设备名称
    uuid: '00001101-...',  // 服务 UUID(连接 / 数据事件)
    state: 4,              // 连接状态(onConnectionStateChanged)
    adapterState: 12,      // 适配器状态(onBluetoothAdapterStateChanged)
    bondState: 12,         // 配对状态(设备相关事件)
    deviceType: 1,         // 0 未知 | 1 经典 | 2 低功耗 | 3 双模
    rssi: -60,             // 信号强度(onDeviceFound,单位 dBm)
    tag: 'req1',           // 写入标识(onWrite)
    hex: '0102FF',         // 十六进制(onRead / onWrite,大写无分隔符)
    text: '...',           // UTF-8 文本(onRead / onWrite,二进制可能乱码)
    base64: '...',         // Base64(onRead)
    length: 3,             // 字节长度(onRead / onWrite)
    success: true,         // 写入是否成功(onWrite)
    discoveryErrorCode: 0, // 搜索错误码(onDiscoveryError):0 缺定位权限 | 1 位置服务未开启 | 2 搜索失败 |
                           // 3 缺扫描权限 | 4 缺连接权限
    message: '...',        // 错误描述(onDiscoveryError)
    timestamp: 1762300000000 // 事件时间戳(毫秒)
}

写入结果(ClassicWriteResult)

{
    address: '00:11:22:33:44:55', // 设备 MAC
    uuid: '00001101-...',         // 服务 UUID
    tag: 'req1',                  // 写入标识(未传 tag 时由插件生成)
    hex: '0102FF',                // 实际写入的十六进制
    length: 3,                    // 字节数
    cost: 12,                     // 从入队到写完耗时(毫秒)
    errMsg: '写入成功'
}

权限结果(ClassicPermissionResult)

{
    list: [{ name: 'android.permission.BLUETOOTH_SCAN', granted: true }],
    allGranted: true,                  // 是否全部授予
    permanentlyDenied: []              // 被永久拒绝(勾选过「不再询问」),需引导用户去系统设置
}

配对状态(bondState)

bondState 取自 Android 系统配对状态常量(BluetoothDevice.BOND_*),插件原样透传,不做二次映射:

值 常量 含义
10 BOND_NONE 未配对(从未配对,或已解除配对)
11 BOND_BONDING 配对中(系统正在配对,可能正在弹配对码 / 确认框)
12 BOND_BONDED 已配对(系统已保存密钥,可以直接发起 SPP 连接)

出现位置(四处含义一致):getBondState 返回的 bondState、getPairedDevices 返回的设备项、onDeviceFound 事件,以及 onBondStateChanged 事件(配对状态变化时主动推送)。

配对结果请统一监听 onBondStateChanged:createBond / removeBond / clearBondDevices 发起后,系统会通过该事件回传 11(配对中)、12(已配对)或 10(解除配对);在系统设置里手动配对/解除配对同样会收到。onConnectionStateChanged 的 2(配对中)/ 3(已配对)只在该设备已存在连接对象时才会出现,不能作为唯一的配对结果来源。

getBondState({
    address: '00:11:22:33:44:55',
    success: (res) => {
        if (res.bondState === 12) {
            // 已配对,可直接 connect
        } else if (res.bondState === 11) {
            // 配对中:等待系统弹框确认,结果看 onBondStateChanged 的 bondState
        } else {
            // 未配对:先 createBond
        }
    }
})

注意区分两套取值:bondState 是系统配对状态(10 / 11 / 12),state 是插件连接状态(0 未连接 / 1 连接中 / 2 配对中 / 3 已配对 / 4 已连接 / 5 已释放),不要混用。

错误码

错误码 说明
9270001 参数错误
9270002 未初始化,请先调用 init
9270003 设备不支持蓝牙
9270004 蓝牙未开启,请先开启蓝牙
9270005 缺少蓝牙扫描权限,请先调用 requestPermissions 申请
9270006 缺少蓝牙连接权限,请先调用 requestPermissions 申请
9270007 缺少定位权限或系统位置服务未开启,搜索设备需要定位权限
9270008 蓝牙地址非法或设备不存在
9270009 连接失败
9270010 连接已存在或已连接
9270011 未连接或连接已断开
9270012 连接已释放,请重新 connect
9270013 写入失败
9270014 获取上下文失败
9270015 UUID 格式非法
9270016 配对失败
9270017 取消配对失败
9270018 搜索失败
9270019 连接超时
9270020 操作失败

权限说明

权限 用途
android.permission.BLUETOOTH 经典蓝牙基础权限(Android 11 及以下)
android.permission.BLUETOOTH_ADMIN 搜索、配对等管理操作(Android 11 及以下)
android.permission.BLUETOOTH_SCAN 搜索附近蓝牙设备(Android 12 及以上)
android.permission.BLUETOOTH_CONNECT 连接设备、读取设备名称与适配器信息(Android 12 及以上)
android.permission.ACCESS_FINE_LOCATION 搜索蓝牙设备所需定位权限(插件按 targetSdkVersion ≥ 29 校验,Android 12 及以上同样需要)
android.permission.ACCESS_COARSE_LOCATION 模糊定位权限,Android 11 及以下与精确定位配合使用
android.permission.INTERNET 由依赖库声明合并引入,本插件业务不使用
android.permission.ACCESS_NETWORK_STATE 由依赖库声明合并引入,本插件业务不使用
android.permission.ACCESS_WIFI_STATE 由依赖库声明合并引入,本插件业务不使用
android.permission.CHANGE_WIFI_STATE 由依赖库声明合并引入,本插件业务不使用

注意:搜索设备时插件会同时校验「蓝牙开关 → 扫描权限 → 连接权限 → 精确定位权限 → 系统位置服务」。Android 12 及以上如果不授予定位权限,startDiscovery 会返回 9270007。

隐私、权限声明

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

android.permission.BLUETOOTH android.permission.BLUETOOTH_ADMIN android.permission.BLUETOOTH_CONNECT android.permission.BLUETOOTH_SCAN android.permission.ACCESS_FINE_LOCATION android.permission.ACCESS_COARSE_LOCATION android.permission.INTERNET android.permission.ACCESS_NETWORK_STATE android.permission.ACCESS_WIFI_STATE android.permission.CHANGE_WIFI_STATE

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

插件仅在本机完成蓝牙搜索、配对与数据收发,采集到的设备信息与收发数据不会上传至任何服务器

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

无

暂无用户评论。