更新记录

1.0.4(2026-05-11)

  • 连接接口新增RFCOMM Socket链路类型的服务UUID

1.0.3(2026-05-11)

  • 新增纯血鸿蒙端

1.0.1(2026-05-11)

  • 优化
查看更多

平台兼容性

uni-app(4.87)

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

uni-app x(4.87)

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

yt-uts-bluetooth

基于 UTS 的 Android、HarmonyOS 经典蓝牙 插件:配对列表、扫描周边设备、连接、收发数据、MTU 设置与释放资源。

特别提醒

  • 购买本插件前,请先试用并充分自测确认满足需求之后再行购买;虚拟物品一旦购买之后无法退款。
  • 如有使用上的疑问或 bug,可进交流群联系作者;作者可承接插件定制。
  • 请在合法范围内使用;若使用本插件从事非法开发,本方概不负责。
  • 试用需自定义基座(见 package.jsonuni_modules 平台说明)。
  • 当前实现仅支持 App Android、HarmonyOSapp-ios不支持)。
  • android示例安装包
  • 低功耗蓝牙插件可使用这款:低功耗/BLE蓝牙

引入方式

业务侧从 uni_modules 引入 函数类型(类型定义见 utssdk/interface.uts):

import *as BTManager from '@/uni_modules/yt-uts-bluetooth'

权限与初始化

initBluetooth()

  • 作用:申请蓝牙相关权限;全部通过后创建内部经典蓝牙管理器。
  • 参数:无。
  • Android 12(API 31)及以上:申请 BLUETOOTH_SCANBLUETOOTH_CONNECTACCESS_FINE_LOCATION
  • 更低版本:申请 ACCESS_COARSE_LOCATION
  • HarmonyOS: 申请 ohos.permission.ACCESS_BLUETOOTH

未成功拿到权限时,内部管理器不会创建;后续调用 getBondList 等依赖管理器的接口会失败。


API 一览(与 utssdk/app-android/index.uts 导出一致)

函数 说明
initBluetooth() 请求权限并初始化内部管理器
getBondList(options) 获取系统已配对(绑定)设备列表
discoveryBluetooth(para) 开始扫描周边设备
connectBluetoothWithName(options) 按 MAC 连接设备并注册读/连接回调
disconnectBluetooth(address) 按 MAC 断开指定设备
sendData(options) 向已连接设备发送字节或字符串
setMtu(para) 设置分片相关 MTU 下限(见类型说明)
getMtu(para) 查询当前 MTU
destroy() 释放插件内部资源;再次使用需重新 initBluetooth

类型与回调说明

BluetoothDeviceInfo

扫描与配对列表中的设备信息:

  • name:名称
  • address:MAC 地址
  • type:设备类型(系统 BluetoothDevice.getType()
  • alias:别名(若系统支持)

GetBoundDeviceOptions

  • success?(devices: BluetoothDeviceInfo[]):成功返回列表
  • fail?(err: ApiFail):失败;未先调用 initBluetootherrCode90001mes 为「请先调用initBluetooth」

DiscoveryPara(扫描)

  • showEmptyName: boolean:是否把 名称为空 的设备也回调上来
  • btNameFilter?: string:按名称过滤(可选)
  • onDeviceFound(res: BluetoothDeviceInfo)必填,每发现一台设备回调一次;同一次扫描内同一设备可能出现多次,业务可自行去重
  • onDiscoveryStarted?: () => void:扫描开始
  • onDiscoveryFinished?: () => void:扫描结束(正常结束或内部取消后也会收到)
  • onError?: (err: string) => void:扫描无法启动或适配器异常

ConnectBluetoothOptions(连接)

  • address?: string建议使用 MAC 连接;支持 AA:BB:CC:DD:EE:FFAA-BB-... 或连续 12 位十六进制(内部会规范为冒号大写等形式)
  • uuid?: string:RFCOMM socket链路类型的服务UUID。选填默认:”00001101-0000-1000-8000-00805F9B34FB”(大量蓝牙串口模块、车载、打印机使用该 UUID;)
  • readDataHandler?(res: ReadResultInfo):收到字节数据或读通道结束时回调
  • onConnected?(address: string):RFCOMM 连接成功
  • onConnectFailed?(deviceAddress, code, message):连接失败(含配对失败、Socket 连接失败等);code 为字符串形式的错误码
  • onDisconnected?(deviceAddress):断开(常见于主动 disconnect 或读写异常导致关闭;对端主动断开的即时性感知可按需扩展)

ReadResultInfo(读回调)

  • deviceAddress:设备 MAC
  • data: number[]:原始字节(数组形式)
  • hexValue / utf8Value / gbkValue:插件侧附加转换结果(便于调试或文本协议)
  • state'0' 表示读到一段数据;'1' 表示 读循环结束(如套接字关闭、disconnect
  • message:说明文案

注意:单次回调 不等于 一条完整业务报文;粘包/分包请在协议层拼接解析。

SendDataOptions(发送)

  • deviceAddress:目标 MAC(需已连接)
  • data?: number[]value?: string若同时存在,data 优先,按原始字节发送
  • 仅发字符串时:
    • encoding?: number0 = UTF-8,1 = GBK,2 = 十六进制字符串(可含空格;偶数位 0-9A-Fa-f,解码为字节后发送)
  • mtuOverride?: number:可选,覆盖本次写入的分片下限(字节,范围见与你底层 YtClassicBtManager 约定,类型注释为 1~65535)
  • onWriteSuccess?(deviceAddress) / onWriteFailed?(deviceAddress, code, message):写成功或失败

SetMtuPara / GetMtuPara

  • deviceAddress:设备 MAC
  • SetMtuPara.mtu:分片下限(字节)
  • SetMtuPara.mtuHandle(success: boolean):设置是否成功
  • GetMtuPara.mtuHandle(mtu: number):返回当前 MTU

ApiFail

  • errCode: number
  • mes: string

推荐使用顺序

  1. 调用 initBluetooth(),确认权限已授予(可通过 getBondList 是否成功侧面验证)。
  2. 使用 getBondList 取已配对设备,或使用 discoveryBluetooth 搜周边并在 onDeviceFound 里收集列表。
  3. connectBluetoothWithName 传入目标 address,在 onConnected / readDataHandler 中处理连接与数据。
  4. sendData 发送数据;需要时 setMtu / getMtu
  5. disconnectBluetooth(address) 断开;不用蓝牙时 destroy()

权限清单

插件声明的权限以 package.jsondcloudext.declaration.permissions 为准(含定位、经典蓝牙与 Android 12+ 的扫描/连接等)。打包前请确认与业务隐私合规一致。


uniapp完整示例

<template>
    <view class="content">

        <view
            style="font-size: 28rpx;color: cadetblue;display: flex;flex-direction: column;background-color: azure;width: 750rpx;display: flex;align-items: center;justify-content: center;">
            <text>读取utf-8数据:{{blueToothValue_utf8}}</text>
            <text>读取HEX数据:{{blueToothValue_hex}}</text>
            <text>读取number[]数据:{{blueToothValue_number}}</text>
        </view>

        <view class="header">
            <view class="btn" @click="boundDevices()">获取已绑定设备</view>
            <view class="btn" @click="scanDevices()">扫描蓝牙</view>
            <view class="btn" @click="closeBluetooth()">断开蓝牙</view>
            <view class="btn" @click="sendDataAction()">发送数据</view>
        </view>
        <view class="header">
            <view class="btn" @click="setMtuAction()">设置MTU</view>
            <view class="btn" @click="getMtuAction()">获取MTU</view>
            <view class="btn" @click="destroy()">释放资源</view>
        </view>
        <view style="width: 750rpx;display: flex;flex-direction: column;" v-if="bondDeviceList.length>0">
            <view
                style="width: 750rpx;height: 60rpx;background-color: bisque;display: flex;align-items: center;justify-content: center;">
                <text>已配对设备</text>
            </view>
            <scroll-view class="bound_list" scroll-y="true">
                <view class="cell" style="background-color: azure;" v-for="(item,index) in bondDeviceList"
                    :key="'bondDevice'+index" @click.stop="connectBluetooth(item.address)">
                    <text style="color:blueviolet;">名称:{{item.name}}</text>
                    <text style="color: blue;">地址:{{item.address}}</text>
                    <view class="line" style="width: 750rpx;height: 1px;background-color: rgba(0, 0, 0, 0.4);"></view>
                </view>
            </scroll-view>
        </view>
        <view style="width: 750rpx;display: flex;flex-direction: column;" v-if="discoveryList.length>0">
            <view
                style="width: 750rpx;height: 60rpx;background-color: bisque;display: flex;align-items: center;justify-content: center;">
                <text>扫描到的设备</text>
            </view>
            <scroll-view class="list" scroll-y="true">
                <view class="cell" style="background-color: azure;" v-for="(item,index) in discoveryList"
                    :key="'bondDevice'+index" @click.stop="connectBluetooth(item.address)">
                    <text style="color:blueviolet;">名称:{{item.name}}</text>
                    <text style="color: blue;">地址:{{item.address}}</text>
                    <view class="line" style="width: 750rpx;height: 1px;background-color: rgba(0, 0, 0, 0.4);"></view>
                </view>
            </scroll-view>
        </view>
    </view>
</template>

<script>
    import * as BTManager from '@/uni_modules/yt-uts-bluetooth'
    export default {
        data() {
            return { //as BluetoothDeviceInfo[]
                bondDeviceList: [], //已绑定蓝牙列表
                blueToothValue_utf8: '', //蓝牙返回的数据
                blueToothValue_hex: '',
                blueToothValue_number: '',
                discoveryList: [], //搜索周边蓝牙设备,
                deviceAddress: '' //当前连接蓝牙的地址

            }
        },
        onLoad() {
            this.initBluetoothAction()
        },
        methods: {
            initBluetoothAction() {
                BTManager.initBluetooth()
            },
            boundDevices() {
                BTManager.getBondList({
                    success: (res) => {
                        console.log(res)
                        this.bondDeviceList = res
                    },
                    fail: (error) => {

                    }
                })
            },
            scanDevices() {
                this.discoveryList = [];
                BTManager.discoveryBluetooth({
                    showEmptyName: false,
                    onDeviceFound: (res) => {
                        this.discoveryList.push(res)
                    },
                    onDiscoveryStarted: () => {
                        console.log('扫描开始')
                    },
                    onDiscoveryFinished: () => {
                        console.log('扫描完成')
                    },
                    onError: (err) => {
                        console.log(err);
                    }
                })
            },
            closeBluetooth() {
                BTManager.disconnectBluetooth(this.deviceAddress)
            },
            sendDataAction() {
                BTManager.sendData({
                    value: 'hello world',
                    deviceAddress: this.deviceAddress,
                    encoding: 1,
                    onWriteSuccess: (devideAdress) => {
                        console.log(`${devideAdress}写入成功`)
                    },
                    onWriteFailed: (deviceAddress, code, message) => {
                        console.log(`${deviceAddress}写入失败---code:${code}----message:${message}`);
                    }
                })
            },
            connectBluetooth(address) {
                BTManager.connectBluetoothWithName({
                    address: address,
                    onConnected: (address) => {
                        console.log(`连接成功:${address}`);
                        this.deviceAddress = address;
                    },
                    onConnectFailed: (address, code, mes) => {
                        console.log(`${address}连接失败--code:${code}---mes:${mes}`)
                    },
                    onDisconnected: (address) => {
                        console.log(`${address}已断开连接`)
                        this.deviceAddress = "";
                    },
                    readDataHandler: (result) => {
                        this.blueToothValue_utf8 = result.utf8Value ?? "";
                        this.blueToothValue_hex = result.hexValue ?? "";
                        this.blueToothValue_number = result.data.toString() ?? "";
                    }
                })
            },
            //获取mtu
            setMtuAction() {
                BTManager.setMtu({
                    deviceAddress: this.deviceAddress,
                    mtu: 200,
                    mtuHandle: (res) => {
                        console.log('设置mtu:' + res)
                    }
                })
            },
            getMtuAction() {
                BTManager.getMtu({
                    deviceAddress: this.deviceAddress,
                    mtuHandle: (res) => {
                        console.log('获取mtu:' + res)
                    }
                })
            },
            //释放资源
            destroy() {
                BTManager.destroy()
            }
        }
    }
</script>

<style>
    .content {
        width: 750rpx;
        display: flex;
        height: 100%;
        flex-direction: column;
    }

    .header {
        width: 750rpx;
        display: flex;
        flex-direction: row;
        align-items: center;
        padding: 0 20rpx;
        box-sizing: border-box;
        margin-top: 20rpx;
    }

    .btn {
        display: flex;
        height: 80rpx;
        padding: 0 5rpx;
        align-items: center;
        justify-content: center;
        background-color: cadetblue;
        color: white;
        margin-right: 20rpx;
        font-size: 28rpx;
        border-radius: 6rpx;
    }

    .bound_list {
        width: 750rpx;
        height: 300rpx;
    }

    .list {
        width: 750rpx;
        height: 600rpx;
    }

    .cell {
        display: flex;
        flex-direction: column;
        justify-content: center;
        padding: 10rpx;
        box-sizing: border-box;
        background-color: antiquewhite;
    }
</style>

uniapp-x完整示例

<template>
    <view class="content">

        <view
            style="font-size: 28rpx;color: cadetblue;height: 80rpx;background-color: azure;width: 750rpx;display: flex;align-items: center;justify-content: center;">
            <text>读取数据:{{blueToothValue}}</text>
        </view>

        <view class="header">
            <view class="btn" @click="boundDevices()">获取已绑定设备</view>
            <view class="btn" @click="scanDevices()">扫描蓝牙</view>
            <view class="btn" @click="closeBluetooth()">断开蓝牙</view>
            <view class="btn" @click="sendDataAction()">发送数据</view>
        </view>
        <view class="header">
            <view class="btn" @click="setMtuAction()">设置MTU</view>
            <view class="btn" @click="getMtuAction()">获取MTU</view>
        </view>
        <view style="width: 750rpx;display: flex;flex-direction: column;" v-if="bondDeviceList.length>0">
            <view
                style="width: 750rpx;height: 60rpx;background-color: bisque;display: flex;align-items: center;justify-content: center;">
                <text>已配对设备</text>
            </view>
            <scroll-view class="bound_list" scroll-y="true">
                <view class="cell" style="background-color: azure;" v-for="(item,index) in bondDeviceList"
                    :key="'bondDevice'+index" @click.stop="connectBluetooth(item.name,item.address)">
                    <text style="color:blueviolet;">名称:{{item.name}}</text>
                    <text style="color: blue;">地址:{{item.address}}</text>
                    <view class="line" style="width: 750rpx;height: 1px;background-color: rgba(0, 0, 0, 0.4);"></view>
                </view>
            </scroll-view>
        </view>
        <view style="width: 750rpx;display: flex;flex-direction: column;" v-if="discoveryList.length>0">
            <view
                style="width: 750rpx;height: 60rpx;background-color: bisque;display: flex;align-items: center;justify-content: center;">
                <text>扫描到的设备</text>
            </view>
            <scroll-view class="list" scroll-y="true">
                <view class="cell" style="background-color: azure;" v-for="(item,index) in discoveryList"
                    :key="'bondDevice'+index" @click.stop="connectBluetooth(item.name,item.address)">
                    <text style="color:blueviolet;">名称:{{item.name}}</text>
                    <text style="color: blue;">地址:{{item.address}}</text>
                    <view class="line" style="width: 750rpx;height: 1px;background-color: rgba(0, 0, 0, 0.4);"></view>
                </view>
            </scroll-view>
        </view>
    </view>
</template>

<script>
    import *as BTManager from '@/uni_modules/yt-uts-bluetooth'
    export default {
        data() {
            return {//as BluetoothDeviceInfo[]
                bondDeviceList: [] as BTManager.BluetoothDeviceInfo[], //已绑定蓝牙列表
                blueToothValue: '', //蓝牙返回的数据
                discoveryList: [] as BTManager.BluetoothDeviceInfo[],//搜索周边蓝牙设备
                deviceAddress: '' //当前连接蓝牙的地址
            }
        },
        onLoad() {
            this.initBluetoothAction()
        },
        methods: {
            initBluetoothAction() {
                BTManager.initBluetooth()
            },
            boundDevices() {
                BTManager.getBondList({
                    success: (res : BTManager.BluetoothDeviceInfo[]) => {
                        console.log(res)
                        this.bondDeviceList = res
                    },
                    fail: (error : BTManager.ApiFail) => {

                    }
                } as BTManager.GetBoundDeviceOptions)
            },
            scanDevices() {
                this.discoveryList = [];
                BTManager.discoveryBluetooth({
                    showEmptyName: false,
                    onDeviceFound: (res) => {
                        this.discoveryList.push(res)
                    },
                    onDiscoveryStarted: () => {
                        console.log('扫描开始')
                    },
                    onDiscoveryFinished: () => {
                        console.log('扫描完成')
                    },
                    onError: (err) => {
                        console.log(err);
                    }
                } as BTManager.DiscoveryPara)
            },
            closeBluetooth() {
                BTManager.disconnectBluetooth(this.deviceAddress)
            },
            sendDataAction() {
                BTManager.sendData({
                    value: 'hello world',
                    deviceAddress: this.deviceAddress,
                    encoding: 1,
                    onWriteSuccess: (devideAdress : string) => {
                        console.log(`${devideAdress}写入成功`)
                    },
                    onWriteFailed: (deviceAddress : string, code : number, message : string) => {
                        console.log(`${deviceAddress}写入失败---code:${code}----message:${message}`);
                    }
                } as BTManager.SendDataOptions)
            },
            connectBluetooth(deviceName : string, address : string) {
                BTManager.connectBluetoothWithName({
                    address: address,
                    onConnected: (address : string) => {
                        console.log(`连接成功:${address}`);
                        this.deviceAddress = address;
                    },
                    onConnectFailed: (address : string, code : string, mes : string) => {
                        console.log(`${address}连接失败--code:${code}---mes:${mes}`)
                    },
                    onDisconnected: (address) => {
                        console.log(`${address}已断开连接`)
                    },
                    readDataHandler: (result : BTManager.ReadResultInfo) => {
                        // console.log(result.utf8Value ?? "")
                        this.blueToothValue = result.utf8Value ?? "";
                    }
                } as BTManager.ConnectBluetoothOptions)
            },
            //获取mtu
            setMtuAction() {
                BTManager.setMtu({
                    deviceAddress: this.deviceAddress,
                    mtu: 100,
                    mtuHandle: (res) => {
                        console.log('设置mtu:' + res)
                    }
                } as BTManager.SetMtuPara)
            },
            getMtuAction() {
                BTManager.getMtu({
                    deviceAddress: this.deviceAddress,
                    mtuHandle: (res) => {
                        console.log('获取mtu:' + res)
                    }
                } as BTManager.GetMtuPara)
            }
        }
    }
</script>

<style>
    .content {
        width: 750rpx;
        display: flex;
        height: 100%;
        flex-direction: column;
    }

    .header {
        width: 750rpx;
        display: flex;
        flex-direction: row;
        align-items: center;
        padding: 0 20rpx;
        box-sizing: border-box;
        margin-top: 20rpx;
    }

    .btn {
        display: flex;
        height: 80rpx;
        padding: 0 5rpx;
        align-items: center;
        justify-content: center;
        background-color: cadetblue;
        color: white;
        margin-right: 20rpx;
        font-size: 28rpx;
        border-radius: 6rpx;
    }

    .bound_list {
        width: 750rpx;
        height: 300rpx;
    }

    .list {
        width: 750rpx;
        height: 600rpx;
    }

    .cell {
        display: flex;
        flex-direction: column;
        justify-content: center;
        padding: 10rpx;
        box-sizing: border-box;
        background-color: antiquewhite;
    }
</style>

隐私、权限声明

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

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <!--Android 12以后--> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <!-- 手机当外围向外广播 --> <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

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

插件不采集任何数据

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