更新记录

1.0.1(2024-09-16)

  1. 优化Android代码告警问题

1.0.0(2024-08-16)

  1. 判断蓝牙是否打开,打开/关闭蓝牙
  2. 蓝牙扫描,获取蓝牙名、mac、信号强度、广播数据等
  3. 设置MTU
  4. 获取service、characteristic
  5. 蓝牙通讯,读、写、notify

平台兼容性

Vue2 Vue3
App 快应用 微信小程序 支付宝小程序 百度小程序 字节小程序 QQ小程序
HBuilderX 3.6.8,Android:4.4,iOS:9 × × × × × ×
钉钉小程序 快手小程序 飞书小程序 京东小程序
× × × ×
H5-Safari Android Browser 微信浏览器(Android) QQ浏览器(Android) Chrome IE Edge Firefox PC-Safari
× × × × × × × × ×

ble蓝牙扫描连接收发数据

功能

  1. 判断蓝牙是否打开,打开/关闭蓝牙
  2. 蓝牙扫描,获取蓝牙名、mac、信号强度、广播数据等
  3. 设置MTU
  4. 获取service、characteristic
  5. 蓝牙通讯,读、写、notify

蓝牙分为中心设备(Central、Master、主设备、客户端)和外围设备(Peripheral、Slave、从设备、服务端) 手机做为客户端可以连接多个蓝牙设备,所以手机又可以叫中心设备(Central),蓝牙设备叫外围设备(Peripheral)。 例如:通过手机蓝牙开启共享单车,手机称为中心设备,共享单车称为外围设备

本插件是中心设备(Central、Master、主设备、客户端)

外围设备插件请使用https://ext.dcloud.net.cn/plugin?name=wrs-uts-bluetoothslave

快速接入

  1. 拷贝demo示例里的AndroidManifest.xml、Info.plist到项目根目录
  2. 集成插件步骤请参考https://www.cnblogs.com/wenrisheng/p/18323027

接口


import {
    UTSBluetoothCenter
} from "@/uni_modules/wrs-uts-bluetoothcenter"
let bluetoothcenter = new UTSBluetoothCenter()
  • 设置回调

// 设置回调
bluetoothcenter.setCallback((resp) => {
    let opt = resp.opt;
    switch (opt) {
        // 蓝牙状态改变,仅支持iOS
        case "onCentralManagerDidUpdateState": {
            // state:
            // 0: CBManagerStateUnknown
            // 1: CBManagerStateResetting
            // 2: CBManagerStateUnsupported
            // 3: CBManagerStateUnauthorized
            // 4: CBManagerStatePoweredOff
            // 5: CBManagerStatePoweredOn
            let state = resp.state
            console.log("state:" + state)

            if (state == 5) {
                // 蓝牙已经打开
            } else if (state == 4) {
                // 蓝牙已关闭
                // this.showModel("蓝牙已关闭,是否打开?", () => {
                //  UTSBluetoothCenter.openSettingApp()
                // })
            } else if (state == 3) {

            } else {

            }
        }
        break;
        // 扫描到蓝牙设备
        case "onScanBluetooth": {
            let device = resp.device
            let name = device.name
            // {"opt":"onScanBluetooth","device":{"name":"MI MAX 3","deviceId":"32A699B6-AC3B-00A9-218A-3014E74A975F"},"rssi":-44,"isConnectable":1}
            // {"device":{"mac":"FF:FF:99:87:09:75","deviceId":"NEMR99870975FF:FF:99:87:09:75","name":"NEMR99870975","rssi":-94},"advertisementData":{"manufacturerData":{"id":20563,"data":[75,29,64,32,64]},"txPowerLevel":3,"serviceUUIDs":["FDF0"],"localName":"NEMR99870975"},"opt":"onScanBluetooth"}
            // 没有蓝牙名的过滤掉
            if (name) {
                if (name !== "MI MAX 3") {
                    // console.log(JSON.stringify(resp))
                    return
                }

                // 已经扫描到的蓝牙也过滤下,防止重复扫描问题
                let deviceId = device.deviceId
                let isExist = false
                for (let i = 0; i < this.deviceArray.length; i++) {
                    if (deviceId == this.deviceArray[i].device.deviceId) {
                        isExist = true
                        break
                    }
                }
                if (!isExist) {
                    this.deviceArray.push(resp)
                }

            }
        }
        break;
        // 蓝牙连接成功
        case "onConnectSuccess": {

            this.showMsg("蓝牙连接成功")
        }
        break;
        // 蓝牙连接失败
        case "onConnectFail": {
            this.showMsg("蓝牙连接失败:" + JSON.stringify(resp))
        }
        break;
        // 蓝牙断开连接
        case "onDisConnected": {
            // 高版本的某些iOS系统,如果发现连接成功后又马上断开了,报下面这种错误时,需要先在设置-蓝牙里面手动进行配对连接上蓝牙后,再来通过代码连接
            // Error Domain=CBErrorDomain Code=7 "The specified device has disconnected from us." UserInfo={NSLocalizedDescription=The specified device has disconnected from us.
            this.showMsg("蓝牙断开连接:" + JSON.stringify(resp))
        }
        break;
        // 发现characteristic特征值
        case "onFindCharacteristic": {
            if (this.isAndroid) {
                resp.service = JSON.parse(resp.service)
            }
            console.log(JSON.stringify(resp))

            var deviceId = resp.device.deviceId;
            var bluetooth = this.getBluetooth(deviceId);

            let service = resp.service
            // let characteristics = resp.characteristics
            // this.$set(service, "characteristics", characteristics);

            if (!bluetooth.services) {
                this.$set(bluetooth, "services", []);
            }
            bluetooth.services.push(service);
        }
        break;
        // 收到数据
        case "onCharacteristicChanged": {
            let value = resp.value
            this.showMsg("收到数据:" + JSON.stringify(resp))
        }
        break;
        default:
            break;
    }
})
  • 蓝牙初始化

var params = {};
if (this.isAndroid) {

} else {
    params.CBCentralManagerOptionShowPowerAlertKey = true;
}
// 初始化
bluetoothcenter.initBluetooth(params);
  • 扫描蓝牙

扫描结果在回调里bluetoothcenter.setCallback((resp) => {}) -> onScanBluetooth


let params = {}
// params.services = ["xxx", "xxx"]
// params.CBCentralManagerScanOptionAllowDuplicatesKey = true // 仅支持iOS
bluetoothcenter.startScanBluetooth(params)

扫描到的数据主要包含有蓝牙名、rssi、mac、广播数据(蓝牙名、厂家数据、serviceUUIDs)等


ios: {"advertisementData":{"manufacturerData":[224,7,204,20,188,82,161,242,2,0],"isConnectable":1,"localName":"EDIFIER BLE"},"opt":"onScanBluetooth","device":{"name":"EDIFIER BLE","rssi":-92,"deviceId":"6EAB2BCC-001E-6664-3E1D-34004BD5C2EF"}}
android: {"device":{"mac":"FF:FF:99:87:09:75","deviceId":"NEMR99870975FF:FF:99:87:09:75","name":"NEMR99870975","rssi":-94},"advertisementData":{"manufacturerData":{"id":20563,"data":[75,29,64,32,64]},"txPowerLevel":3,"serviceUUIDs":["FDF0"],"localName":"NEMR99870975"},"opt":"onScanBluetooth"}

扫描不到蓝牙问题排查:

  1. Android是否有调用请求权限接口

// 请求Android动态权限
this.requestPermission([
    "android.permission.BLUETOOTH_SCAN",
    "android.permission.BLUETOOTH_CONNECT",
    "android.permission.BLUETOOTH_ADMIN",
    "android.permission.BLUETOOTH",
    "android.permission.ACCESS_FINE_LOCATION",
    "android.permission.ACCESS_COARSE_LOCATION",
    "android.permission.READ_EXTERNAL_STORAGE",
    "android.permission.WRITE_EXTERNAL_STORAGE"
])
  1. 某些蓝牙设备需要现在设置-> 蓝牙里面先进行蓝牙连接配对后才能扫描
  2. 将手机蓝牙功能先关闭重新打开后再扫描
  3. Android设备的定位、蓝牙功能是否已经开启
  • 停止扫描

bluetoothcenter.stopScanBluetooth()
  • 连接蓝牙

Android可以通过deviceId或mac连接蓝牙,iOS只能通过deviceId连接蓝牙

连接结果在回调里bluetoothcenter.setCallback((resp) => {}) -> onConnectSuccess、onConnectFail

连接成功会会自动查找service/characteristic,查找结果在回调的onFindCharacteristic里面

characteristic的读写notify属性判断请参考demo


let params = {}
params.deviceId = model.device.deviceId
// params.mac = “A4:C1:38:A1:46:C8”
console.log(`params:${JSON.stringify(params)}`)
let flag = bluetoothcenter.connectBluetooth(params)
if (!flag) {
    console.log("参数错误")
}
  • 断开连接

let params = {}
params.deviceId = model.device.deviceId
let flag = bluetoothcenter.disConnectBluetooth(params)
if (!flag) {
    console.log("参数错误")
}
  • 打开characteristic notify通知,characteristic只有打开notify通知后才能收到对方发来的数据

开启后,收到的数据在回调里bluetoothcenter.setCallback((resp) => {}) -> onCharacteristicChanged(let value = resp.value) value是十六进制数组,如果需要ascii、十六进制字符串、modbus等数据转换,请使用插件https://ext.dcloud.net.cn/plugin?id=19206


var bluetooth = this.deviceArray[i];
var service = bluetooth.services[j];
var characteristic = service.characteristics[k];
bluetoothcenter.openOrStopNotify({
    deviceId: bluetooth.device.deviceId,
    serviceUuid: service.uuid,
    characteristicUuid: characteristic.uuid,
    isOpen: true // true: 打开, false: 关闭
}, (resp) => {
    if (resp.flag) { // 打开成功

    } else { // 打开失败

    }
});
  • 发送数据

value目前只支持十六进制数组,如果需要ascii、十六进制字符串、modbus等数据转换,请使用插件https://ext.dcloud.net.cn/plugin?id=19206


var bluetooth = this.deviceArray[i];
var service = bluetooth.services[j];
var characteristic = service.characteristics[k];
bluetoothcenter.writeData({
    deviceId: bluetooth.device.deviceId,
    serviceUuid: service.uuid,
    characteristicUuid: characteristic.uuid,
    value: [0x01, 0xFF], // 要发送的数据
    type: 0 // 写类型,仅支持iOS, 0: CBCharacteristicWriteWithResponse 1: CBCharacteristicWriteWithoutResponse
}, (resp) => {

});
  • 读数据

var bluetooth = this.deviceArray[i];
var service = bluetooth.services[j];
var characteristic = service.characteristics[k];
bluetoothcenter.readData({
    deviceId: bluetooth.device.deviceId,
    serviceUuid: service.uuid,
    characteristicUuid: characteristic.uuid
}, (resp) => {

});
  • 设置mtu,仅支持Android

iOS蓝牙没有MTU,每次发送的数据大小由系统决定,如果数据包过大,自行拆包分段发送


let mtu = 100
UTSBluetoothCenter.setMtu(mtu, (resp)=>{

})
  • 蓝牙是否已经打开,仅支持Android

ios蓝牙开启状态的监听在回调的onCentralManagerDidUpdateState里


let isEnabled = UTSBluetoohSlave.isEnable()
  • 打开蓝牙,仅支持Android

 UTSBluetoohSlave.enable()
  • 关闭蓝牙,仅支持Android

UTSBluetoohSlave.disable()
  • 设置蓝牙名,仅支持Android

let name = "xxx"
let isSuc = UTSBluetoohSlave.setName(name)
  • 跳到蓝牙设置界面,仅支持Android

UTSBluetoohSlave.toBluetoothPage()
  • 设置蓝牙可见性,仅支持Android

// 有时候虽然设备的蓝牙和定位权限都打开了,但是扫描不到设备(除非以前配对过)。只有进入蓝牙页面,才能被扫描搜索到。这个就涉及到蓝牙的可见性,为了保护隐私默认是不可见的,需要打开蓝牙可见性,才能被别的设备扫描搜索到
//设置蓝牙可见性的时间,方法本身规定最多可见300秒,会弹出一个确定的窗口
UTSBluetoothCenter.setDiscoverableTime(300)

隐私、权限声明

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

蓝牙、定位、读写

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

插件不采集任何数据

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

使用中有什么不明白的地方,就向插件作者提问吧~ 我要提问