久智环境
久智环境
  • 发布:2023-11-20 13:59
  • 更新:2024-01-20 08:51
  • 阅读:399

【报Bug】Android下蓝牙监听特征值变化回调不执行

分类:uni-app

产品分类: uniapp/App

PC开发环境操作系统: Windows

PC开发环境操作系统版本号: 10

HBuilderX类型: 正式

HBuilderX版本号: 3.96

手机系统: Android

手机系统版本号: Android 13

手机厂商: 小米

手机机型: 小米10

页面类型: vue

vue版本: vue2

打包方式: 云端

项目创建方式: HBuilderX

示例代码:
{  
            "uuid": "CBA1D466-344C-4BE3-AB3F-189F80DD7518",  
            "properties": {  
                "read": true,  
                "write": true,  
                "notify": true,  
                "indicate": true  
            }  
        }  

uni.notifyBLECharacteristicValueChange({  
        state: true,  
        deviceId: deviceId, // 设备ID  
        serviceId: serviceId, // 服务UUID,  
        characteristicId: characteristicId, // 这里的特征值就是上方获取的,支持notify  
        success(res) {  
            listenValueChange()  
        },  
        fail(err) {  
            console.error(err)  
        }  
    })  

function listenValueChange() {  
    uni.onBLECharacteristicValueChange(res => {  
        console.log('监听到数据了');  
        // 结果里有个value值,该值为 ArrayBuffer 类型,所以在控制台无法用肉眼观察到,必须将该值转换为16进制  
        let resHex = ab2hex(res.value)  
        // 最后将16进制转换为ascii码,就能看到对应的结果  
        let result = hexCharCodeToStr(resHex)  
        console.log(JSON.parse(result).diameter)  
        uni.$emit('diameter', JSON.parse(result).diameter)  
    })  
}  

操作步骤:

1:初始化蓝牙(√)
2:搜寻蓝牙(√)
3:连接蓝牙(√)
4:启用低功耗蓝牙设备特征值变化时的 notify 功能(√)
5:监听低功耗蓝牙设备的特征值变化事件(×)

预期结果:

预期情况可以接收到特征值变化

实际结果:

onBLECharacteristicValueChange回调函数不执行

bug描述:

Android手机连接蓝牙设备后,蓝牙设备发送数据,app端特征值变化回调函数不执行,此功能在IOS端没有任何问题

2023-11-20 13:59 负责人:无 分享
已邀请:
久智环境

久智环境 (作者)

1:在Android上使用BLE调试助手,发现没有问题,可以正常接收
2:改用plus api方式调用蓝牙,同样无法收到通知

久智环境

久智环境 (作者)

开发过程中发现uni.startBluetoothDevicesDiscovery方法中的参数services必须使用大写的serviceId才可以搜寻到,不知道characteristicId,serviceId这些大小写是否有影响,硬件给到的这两个值都是小写的

久智环境

久智环境 (作者)

有没有官方大佬看下

追梦随想

追梦随想

确实收不到,他大爷的,折腾两天也没搞出来,就卡到最后一步了,实测,用苹果可以收到

  • 久智环境 (作者)

    没有解决,插件市场的也不行,plus api也用过了,没用,真的脑壳疼

    2023-12-19 10:25

追梦随想

追梦随想

我解决了,官方太懒,文档不写清除点。。。
在蓝牙连接后加入代码

uni.setBLEMTU({  
    deviceId: deviceId,  
    mtu: 247    //根据硬件情况设置,否则会报错  
});

一点问题都没有

  • 久智环境 (作者)

    我加了这个还是不行,不知道是不是我的使用姿势不对,但ios好好的。。。

    2023-12-21 10:13

  • 追梦随想

    回复 久智环境: IOS不用加就可以,你看看是不是加错地方了,同时在setBLEMTU内部打印执行结果看看有没有报错

    2023-12-21 11:06

  • 久智环境 (作者)

    回复 追梦随想: setBLEMTU我是放在createBLEConnection成功的回调函数里执行的,ios确实不用加就可以,安卓的我加了也没用,我都怀疑是设备问题,但是我用其他的蓝牙工具又可以

    2023-12-21 11:16

  • 追梦随想

    回复 久智环境: 可以问问硬件佬,或者推荐你一个测试蓝牙的小程序:易加蓝牙助手,图标是饿了么的。。。连接上去试试,如果能收到,那就是你代码问题,不能收到就是设备问题

    2023-12-21 11:25

  • 久智环境 (作者)

    回复 追梦随想: 能给我看看你的代码吗,我的代码顺序是openBluetoothAdapter,startBluetoothDevicesDiscovery,onBluetoothDeviceFound,createBLEConnection,stopBluetoothDevicesDiscovery,setBLEMTU,notifyBLECharacteristicValueChange(这里是提前知道了serviceId和characteristicId),onBLECharacteristicValueChange,我代码看着没有任何问题呀

    2023-12-27 13:37

2***@qq.com

2***@qq.com

我的是Android可以执行,ios时行时不行

追梦随想

追梦随想

<template>  
    <view class="">  
        <dm-data-block height="50" :padding="[0, '30rpx']" customClass="display-flex justify-content-space-between align-items-center">  
            <dm-title :showFlag="false" :name="`共找到 ${device_list.length} 个设备`"></dm-title>  
            <view class="display-flex align-items-center" v-if="searching">  
                <dm-icon name="radar-search" class="animation-rotate-loop"></dm-icon>  
                <dm-gap width="10rpx"></dm-gap>  
                <dm-text fontSize="12" class="text-color-secondary">正在搜索</dm-text>  
            </view>  
            <dm-tag v-else name="搜索设备" @click="search_device">  
                <dm-icon slot="before" name="search" color="#FFF"></dm-icon>  
            </dm-tag>  
        </dm-data-block>  
        <dm-cell-group bgColor="#FFF">  
            <block v-for="(item, index) in device_list" :key="index">  
                <dm-cell customClass="display-flex justify-content-space-between" :border="index + 1 < device_list.length" @click="bluetooth_connect(item.deviceId, index)">  
                    <dm-text class="text-color-convention">{{item.name || item.deviceId}}</dm-text>  
                    <dm-icon v-if="connect_key == index" name="right" color="#0055ff"></dm-icon>  
                    <dm-icon v-else name="arrow-right" color="#dadee6"></dm-icon>  
                </dm-cell>  
            </block>  
            <dm-empty v-if="!device_list.length" height="calc(100vh - 52px)" image="/static/empty/data.png" desc="没有找到相关设备"></dm-empty>  
        </dm-cell-group>  
    </view>  
</template>  

<script>  
export default {  
    onLoad() {  
        this.bluetooth_init();  
    },  
    onUnload() {  
        this.auto_offline = false;  
        uni.closeBluetoothAdapter();  
    },  
    data() {  
        return {  
            is_init: false,     //是否初始化  
            searching: false,   //搜索中  
            device_list: [],    //设备列表  
            connect_key: null,  //连接的设备下标  
            deviceId: '',       //设备ID  
            connect_device: {   //连接的设备相关权限,每个权限内都包含(设备ID、服务ID、特征值ID)  
                read: [],  
                write: [],  
                notify: [],  
                indicate: []  
            },  
            auto_offline: true  //是否是自动断线,用于处理断开提示  
        }  
    },  
    methods: {  
        //初始化蓝牙模块  
        bluetooth_init() {  
            let _this = this;  
            uni.openBluetoothAdapter({  
                success(res) {  
                    _this.is_init = true;  
                    _this.search_device();  
                },  
                fail(err) {  
                    console.log(err);  
                    if ('errCode' in err) {  
                        if (err.errCode == 10001) {  
                            uni.showModal({  
                                content: '请确保手机支持蓝牙功能并开启',  
                                showCancel: false  
                            });  
                        }  
                    } else {  
                        uni.showModal({  
                            content: '请开启小程序蓝牙权限',  
                            showCancel: false,  
                            success() {  
                                uni.openSetting();  
                            }  
                        });  
                    }  
                }  
            });  
        },  
        //搜索设备  
        search_device() {  
            if (!this.is_init) {  
                this.bluetooth_init();  
                return;  
            }  

            let _this = this;  
            _this.searching = true;  
            uni.startBluetoothDevicesDiscovery({  
                success(res) {  
                    uni.onBluetoothDeviceFound((res) => {  
                        _this.device_list.push(res.devices[0]);  
                    });  

                    //10秒后停止搜索  
                    setTimeout(() => {  
                        uni.stopBluetoothDevicesDiscovery();  
                        _this.searching = false;  
                    }, 10000)  
                },  
                fail(err) {  
                    _this.searching = false;  
                }  
            });  
        },  
        //蓝牙连接  
        bluetooth_connect(deviceId, index, timeout = 30) {  
            if (typeof this.connect_key == 'number' && this.deviceId) {  
                if (this.connect_key == index) {  
                    return;  
                } else {  
                    this.auto_offline = false;  
                    this.bluetooth_connect_close();  
                }  
            }  
            uni.showLoading({  
                title: '正在连接...',  
                mask: true  
            })  
            let _this = this;  
            uni.createBLEConnection({  
                deviceId: deviceId,  
                timeout: timeout,  
                success(res) {  
                    _this.connect_key = index;  
                    uni.showToast({  
                        icon: 'success',  
                        title: '连接成功',  
                        success() {  
                            _this.deviceId = deviceId;  
                        }  
                    })  

                    //监听低功耗蓝牙连接状态的改变事件  
                    _this.bluetooth_connect_change();  

                    //获取蓝牙设备所有服务  
                    _this.get_bluetooth_service(deviceId)  
                },  
                fail(err) {  
                    uni.showToast({  
                        icon: 'error',  
                        title: '连接失败',  
                        success() {  
                            console.log('连接失败');  
                            console.log(err);  
                        }  
                    })  
                },  
                complete() {  
                    //设置蓝牙最大传输单元  
                    uni.setBLEMTU({  
                        deviceId: deviceId,  
                        mtu: 247    //根据硬件情况设置,否则会报错  
                    });  
                }  
            });  
        },  
        //监听低功耗蓝牙连接状态的改变事件  
        bluetooth_connect_change() {  
            let _this = this;  
            uni.onBLEConnectionStateChange((res) => {  
                if (!res.connected) {  
                    _this.deviceId = '';  
                    _this.connect_key = null;  
                    _this.connect_device = {  
                        read: [],  
                        write: [],  
                        notify: [],  
                        indicate: []  
                    }  

                    if (_this.auto_offline) {  
                        uni.showToast({  
                            title: '连接已断开',  
                            icon: 'error'  
                        })  
                    }  
                }  
            });  
        },  
        //获取蓝牙设备所有服务  
        get_bluetooth_service(deviceId) {  
            let _this = this;  
            uni.getBLEDeviceServices({  
                deviceId: deviceId,  
                success(res) {  
                    _this.bluetooth_start_work(deviceId, res.services);  
                }  
            });  
        },  
        //蓝牙开始工作  
        async bluetooth_start_work(deviceId, services) {  
            let _this = this;  
            for (let i = 0; i < services.length; i++) {  
                //获取蓝牙设备某个服务中所有特征值  
                await this.get_bluetooth_characteristic(deviceId, services[i].uuid);  
            }  

            //获取设备发出的消息,必须是 notify 或者 indicate  
            if (this.connect_device.notify.length || this.connect_device.indicate.length) {  
                let serviceId = this.connect_device.notify[0].serviceId || this.connect_device.indicate[0].serviceId;  
                let characteristicId = this.connect_device.notify[0].characteristicId || this.connect_device.indicate[0].characteristicId;  
                this.get_device_message(deviceId, serviceId, characteristicId);  
            } else {  
                uni.showModal({  
                    content: '该设备不支持接收消息',  
                    showCancel: false,  
                    success() {  
                        _this.bluetooth_connect_close();  
                    }  
                });  
            }  
        },  
        //获取蓝牙设备某个服务中所有特征值  
        get_bluetooth_characteristic(deviceId, serviceId) {  
            let _this = this;  
            return new Promise((resolve, reject) => {  
                uni.getBLEDeviceCharacteristics({  
                    deviceId: deviceId,  
                    serviceId: serviceId,  
                    success(res) {  
                        res.characteristics.map((item) => {  
                            if (item.properties.read) {  
                                _this.connect_device.read.push({  
                                    deviceId: deviceId,  
                                    serviceId: serviceId,  
                                    characteristicId: item.uuid  
                                });  
                            }  
                            if (item.properties.write) {  
                                _this.connect_device.write.push({  
                                    deviceId: deviceId,  
                                    serviceId: serviceId,  
                                    characteristicId: item.uuid  
                                });  
                            }  
                            if (item.properties.notify) {  
                                _this.connect_device.notify.push({  
                                    deviceId: deviceId,  
                                    serviceId: serviceId,  
                                    characteristicId: item.uuid  
                                });  
                            }  
                            if (item.properties.indicate) {  
                                _this.connect_device.indicate.push({  
                                    deviceId: deviceId,  
                                    serviceId: serviceId,  
                                    characteristicId: item.uuid  
                                });  
                            }  
                        });  
                        resolve();  
                    },  
                    fail(err) {  
                        reject(err);  
                    }  
                });  
            });  
        },  
        //获取设备消息  
        get_device_message(deviceId, serviceId, characteristicId) {  
            let _this = this;  
            uni.notifyBLECharacteristicValueChange({  
                deviceId: deviceId,  
                serviceId: serviceId,  
                characteristicId: characteristicId,  
                state: true,  
                success(res) {  
                    uni.onBLECharacteristicValueChange((res) => {  
                        let resHex = _this.ab2hex(res.value);  
                        let result = _this.hexCharCodeToStr(resHex);  
                        console.log('设备消息:' + result);  
                    });  
                },  
                fail(err) {  
                    console.log(err);  
                }  
            });  
        },  
        //断开与低功耗蓝牙设备的连接  
        bluetooth_connect_close() {  
            uni.closeBLEConnection({  
                deviceId: this.deviceId,  
                success(res) {  
                    console.log(res);  
                }  
            });  
        },  
        //ArrayBuffer转16进度字符串示例  
        ab2hex(buffer) {  
            const hexArr = Array.prototype.map.call(  
            new Uint8Array(buffer),  
                function (bit) {  
                  return ('00' + bit.toString(16)).slice(-2)  
                }  
            )  
            return hexArr.join('')  
        },  
        //将16进制的内容转成我们看得懂的字符串内容  
        hexCharCodeToStr(hexCharCodeStr) {  
            var trimedStr = hexCharCodeStr.trim();  
            var rawStr = trimedStr.substr(0, 2).toLowerCase() === "0x" ? trimedStr.substr(2) : trimedStr;  
            var len = rawStr.length;  
            if (len % 2 !== 0) return "";  
            var curCharCode;  
            var resultStr = [];  
            for (var i = 0; i < len; i = i + 2) {  
                curCharCode = parseInt(rawStr.substr(i, 2), 16);  
                resultStr.push(String.fromCharCode(curCharCode));  
            }  
            return resultStr.join("");  
        }  
    }  
}  
</script>  

<style lang="scss">  
@import '../../uni_modules/dm-ui/libs/animation.scss';  
</style>

不好意思,刚看到,这是全部代码,页面是用我的UI框架 dm-ui

要回复问题请先登录注册