收藏
回答

wx.onBLECharacteristicValueChange偶现回调异常?



import modal from "@/utils/modal";

import {

    mapState

} from "vuex";

import skeyTool from "@/utils/skeyTool";

import utils from "@/utils/utils";


export default {


    data() {

        return {

            connectTime: null,

            isIos: false, //ios特殊处理

            isOpenBluebooth: false,

            isOpenSetting: false,//检测蓝牙未打开 跳转蓝牙设置页

            userLocation: true,//判断Android机型下是否授权了地理位置

            bleAdapterState: false,//蓝牙适配器状态

        }

    },

    mounted() {

        const systemInfo = wx.getSystemInfoSync();

        if (/iPhone/.test(systemInfo.model)) {

            this.isIos = true;

        }


        //针对Android 部分机型需要地理位置授权

        // wx.getSetting({

        //     success(res) {

        //         if (!this.isIos && !res.authSetting['scope.userLocation']) {

        //             wx.authorize({

        //                 scope: 'scope.userLocation',

        //                 success(res) {

        //                     console.log('authorize', 'success');

        //                 },

        //                 fail() {

        //                     this.userLocation = false

        //                     console.log('authorize', 'fail');

        //                 }

        //             })

        //         }

        //     }

        // })

    },

    methods: {

        //用户授权信息判断

        getSetting() {

            let _that = this

            try {

                wx.getSetting({

                    withSubscriptions: true,

                    success(res) {

                        if (res.authSetting['scope.bluetooth']) {

                            _that.initBlueTooth()

                        } else {

                            if (_that.$refs["setBlueRef"]) _that.$refs["setBlueRef"].hide();

                            modal.toast('您拒绝了蓝牙授权')

                            _that.closeBlueTooth()

                        }

                    }

                })

            } catch (error) {

                // console.log(error, 'getSetting');

                throw error

            }

        },


        // 打开手机蓝牙功能

        setBlueTooth() {

            this.isOpenSetting = true

            //ios特殊处理

            if (this.isIos) {

                try {

                    wx.openAppAuthorizeSetting({

                        success: (res) => {

                            this.isOpenBluebooth = true

                            // console.log('您拒绝了蓝牙授权', res);

                            if (this.$refs["setBlueRef"]) this.$refs["setBlueRef"].hide();


                        },

                        fail: (res) => {

                            this.isOpenBluebooth = false

                        },

                    });

                } catch (error) {

                    throw error

                }

            } else {

                //安卓手机打开蓝牙设置页面

                try {

                    wx.openSystemBluetoothSetting({

                        success: (data) => {

                            this.isOpenBluebooth = true

                            if (this.$refs["setBlueRef"]) this.$refs["setBlueRef"].hide();

                        },

                        fail: (err) => {

                            this.isOpenBluebooth = false

                        },

                    });

                } catch (error) {

                    throw error

                }

            }

        },

        //---------------------step1------------------------

        // 判断是否打开了蓝牙

        async initBlueTooth() {

            let _that = this;

            await this.$refs["privacyModal"].show();

            try {

                wx.openBluetoothAdapter({

                    mode: "central",

                    success: function (res) {

                        // 蓝牙已打开直接扫码

                        // 获取蓝牙适配器状态

                        _that.isOpenBluebooth = true

                        _that.getBluetoothAdapter();

                    },

                    fail: function (res) {

                        if (res.errCode == 10001) {

                            uni.hideToast()


                            if (_that.$refs["setBlueRef"]) return _that.$refs["setBlueRef"].show();

                        }

                        _that.isOpenBluebooth = false

                        _that.getSetting()

                    },

                });

            } catch (error) {

                throw error

            }

        },

        //-----------------------step1 end-------------------


        //------------------------step4-------------------

        //获取本机蓝牙适配器状态

        //检测本机蓝牙是否可用

        async getBluetoothAdapter() {

            let _that = this;

            try {

                //获取本机蓝牙适配器状态

                wx.getBluetoothAdapterState({

                    success: function (res2) {

                        // console.log('getBluetoothAdapterState', res2);

                        //跳转到手机系统蓝牙设置页后回到此页面监听蓝牙是否打开

                        if (!res2.available && _that.isOpenSetting) {

                            _that.isOpenSetting = false

                            _that.bleAdapterState = false


                            modal.toast('蓝牙未打开')

                            return

                        }

                        if (res2.errMsg == "getBluetoothAdapterState:ok") {

                            //搜寻附近的蓝牙设备

                            uni.showLoading({

                                title: "连接设备蓝牙中",

                                mask: true,

                            });

                            _that.startBluetoothDevices();

                            _that.isOpenSetting = false

                            _that.bleAdapterState = true

                        }

                    },

                    fail: function (res2) {

                        if (_that.isOpenSetting)

                            uni.hideLoading();

                    },

                });

            } catch (error) {

                throw error


                // console.log(error, "getBluetoothAdapterState");

            }

        },

        //------------------------step4 end-------------------

        //------------------------- step5----------------------

        //开始搜寻附近的蓝牙外围设备。

        async startBluetoothDevices() {

            let _that = this;

            try {

                wx.startBluetoothDevicesDiscovery({

                    success: function (res) {

                        if (res.errCode == 0) {

                            // 监听寻找到新设备的事件

                            _that.onBluetoothDevice();


                        }

                        console.log('startBluetoothDevicesDiscovery', res

                        );

                    },

                    fail: function (res) {

                        if (res.errCode < 0 && res.errMsg.includes('location')) {

                            uni.hideToast()

                            uni.hideLoading()

                            modal.toast('请开启微信定位授权')

                            return

                        }

                        console.log(res, 'startBluetoothDevicesDiscovery');

                        if (res.errCode > 1) modal.toast("连接失败");

                        // if (_that.connectTime) clearTimeout(_that.connectTime);

                        // _that.connectTime = null;

                    },

                });

            } catch (error) {

                // console.log(error, "startBluetoothDevicesDiscovery");

                throw error


            }

        },

        //------------------------- step5 end----------------



        //----------------step6-------------------

        //监听寻找到新设备的事件

        async onBluetoothDevice() {

            let _that = this;

            /**

            advertisData    ArrayBuffer    当前蓝牙设备的广播数据段中的 ManufacturerData 数据段。

            advertisServiceUUIDs    Array.<string>    当前蓝牙设备的广播数据段中的 ServiceUUIDs 数据段

      localName    string    当前蓝牙设备的广播数据段中的 LocalName 数据段

      serviceData    Object    当前蓝牙设备的广播数据段中的 ServiceData 数据段

      connectable    boolean    当前蓝牙设备是否可连接( Android 8.0 以下不支持返回该值 )

       */

            try {

                wx.onBluetoothDeviceFound((res) => {

                    res.devices.length &&

                        res.devices.forEach((device) => {

                            //https://developers.weixin.qq.com/miniprogram/dev/api/device/bluetooth/wx.onBluetoothDeviceFound.html

                            //这里要求柜机外围设备发送ManufacturerData 数据段 (advertisData ArrayBuffer数据类型)


                            if (device.deviceId && device.advertisData && device.localName) {

                                let deviceId = _that.hex2ab(device.advertisData);

                                // 确保蓝牙设备中的advertisData字段有数据

                                if (deviceId) {

                                    //转换后多了一个P 字符?

                                    let new_sim = deviceId.substr(

                                        deviceId.length - 15,

                                        deviceId.length

                                    );

                         

                                    if (_that.sim == new_sim) {

                                        _that.deviceId = device.deviceId;

                                        //筛选完成,连接蓝牙     先连接蓝牙后停止搜寻附近的蓝牙设备

                                        _that.stopBluetooth()

                                        setTimeout(() => {

                                            _that.createBLEConnectionFn(device.deviceId);

                                        }, 400)

                                    }

                                }

                            }

                        });

                });

            } catch (error) {

                uni.hideLoading();

                _that.stopBluetooth();


                throw error


            }

        },

        //------------------step6 end-----------------------


        //-----------------------step7-----------------------

        //连接蓝牙

        async createBLEConnectionFn() {

            let _that = this;

            try {

                //连接蓝牙前先关闭已连接蓝牙

                wx.createBLEConnection({

                    deviceId: _that.deviceId,

                    success: function (res) {

                    

                        //获取连接设备的service服务

                        _that.getBLEDeviceServicesFn(_that.deviceId);

                        uni.hideLoading();

                        uni.showToast({

                            title: "连接设备蓝牙成功",

                            icon: "success",

                            mask: true,

                        });

                        _that.currentIndex = 1;

                        _that.connectSuccess = true

                        _that.connectFlag = true;

                        //监听蓝牙关闭

                        wx.onBLEConnectionStateChange(function (res) {

                  

                     

                            if (!res.connected) {

                    

                                uni.hideLoading()

                                _that.connectFlag = false

                                _that.isConnectIng = false

                                _that.showLoading = false

                                _that.connectSuccess = false

                                // console.log('设备已断开蓝牙连接');

                                modal.toast("设备已断开蓝牙连接");

                                if (_that.$refs["paging"]) {

                                    _that.$refs["paging"].scrollToTop();

                                    _that.$refs["paging"].complete();

                                }


                            }

                        });

                    },

                    fail: function (res) {

                        console.log(res, 'createBLEConnection');

                  

                        _that.stopBluetooth();

                     

                        uni.hideLoading();

                        uni.showToast({

                            title: "连接蓝牙失败",

                            icon: "error",

                            mask: true,

                        });

                        _that.connectSuccess = false

                        if (_that.$refs["paging"]) {

                            _that.$refs["paging"].scrollToTop();

                            _that.$refs["paging"].complete();

                        }

                    },

                });

            } catch (error) {

                throw error


            }

        },

        //----------------------step7 end--------------------------


        //---------------------step8----------------------

        //获取连接设备的service服务

        async getBLEDeviceServicesFn(deviceId) {

            let _that = this;

            try {

                wx.getBLEDeviceServices({

                    deviceId: _that.deviceId,

                    success: function (res) {


                        for (let i = 0; i < res.services.length; i++) {

                            if (res.services[i].isPrimary) {

                                _that.serviceId = res.services[i].uuid;

                                //获取连接设备的所有特征值

                                _that.getBLEDevice(

                                    deviceId,

                                    res.services[i].uuid

                                );

                            }

                        }

                    },

                    fail: function (res) {

                        // console.log("获取蓝牙失败", res);

                    },

                });

            } catch (error) {

                throw error

            }

        },

        //-----------------------step8 end----------------------

        //-----------------------step 9---------------------

        //获取连接设备的所有特征值

        async getBLEDevice(deviceId, serviceId) {

            let _that = this;

            try {

                wx.getBLEDeviceCharacteristics({

                    deviceId: deviceId,

                    serviceId: serviceId,

                    success: function (res) {

                        if (res.errCode == 0) {


                            let characteristicId = res.characteristics;

                            for (var i = 0; i < res.characteristics.length; i++) {

                                if (res.characteristics[i].properties.write) {

                                    _that.characteristicId = characteristicId[i]["uuid"];

                                    //确保设备能够写入数据

                                    let str = "xx" + _that.sim + "ok";

                                    _that.writeBLECharacteristic(str);

                                    //启用低功耗蓝牙设备特征值变化时的 notify 功能

                                    setTimeout(() => {

                                        _that.notifyBLECharacteristic(

                                            deviceId,

                                            serviceId,

                                            characteristicId[i]["uuid"]

                                        );

                                    }, 500);

                                    //设备详情 与终端确定 切换仅4G模式相当于清空WiFi配置


                                    // 没有WiFi列表数据主动获取一次

                                    if (_that.wifiList) {

                                        if (!_that.wifiList.length) _that.getWifiList()

                                    }

                                    // 设置详情页面通过蓝牙清空WiFi配置

                                    if (_that.isClearWifiConf) {

                                        setTimeout(() => {

                                            _that.clearWrite()

                                        }, 500)

                                    }


                                }

                            }

                        } else {

                            // console.log("获取特征值失败");

                            // modal.toast("获取特征值失败");

                        }

                    },

                });

            } catch (error) {

                throw error

            }

        },

        //---------------------------step11------------------------

        //启用低功耗蓝牙设备特征值变化时的 notify 功能

        async notifyBLECharacteristic(

            deviceId,

            serviceId,

            characteristicId

        ) {

            let _that = this;

            try {

                wx.notifyBLECharacteristicValueChange({

                    deviceId: deviceId,

                    serviceId: serviceId,

                    characteristicId: characteristicId,

                    state: true,

                    success: function (res) {

                        // console.log("启用低功耗蓝牙设备特征值变化时的 notify 功能", res);

                        /*用来监听手机蓝牙设备的数据变化*/

                        _that.onBLECharacteristic();

                        _that.watchBleConnectionState()

                    },

                    fail: function (res) {

                        modal.toast('启用notify失败')

                    },

                });

            } catch (error) {

                modal.toast('启用notify失败')

                // console.log(error, "notifyBLECharacteristicValueChange");

                throw error

            }

        },

        //--------------------------------ste11 end--------------------


        //--------------------------------step12 ----------------------

        onBLECharacteristic() {

            let _that = this;


            try {

                wx.onBLECharacteristicValueChange(function (res) {

                    let flag = _that.hex2ab(res.value); //针对WiFi列表发送完成

                    console.log('通过hex2ab解析的数据', flag);

                    console.log(res, res.value, 'onBLECharacteristic');

                    if (_that.sendIngWifi) {

                        if (flag === "sendWifiListOK") {

                            _that.connectFlag = true;

                            uni.hideLoading()

                            _that.stopSendWifi();

                            _that.sendIngWifi = false;

                            _that.initWifiList(_that.wifiListStr);

                        } else {

                            let val = _that.str2abEmpty(res.value);

                            _that.wifiListStr += val;

                            console.log('通过str2abEmpty解析的数据', val,);

                        }

                    }

                    //当前WiFi连接成功后会切换模式

                    if (flag == "WifiConnectOK") {

                        _that.connectFlag = true;

                        //控制设备连接WiFi成功

                        _that.isConnectIng = false

            

                    } else if (flag == "WifiConnectFailed") {

                        uni.showToast({

                            title: "WiFi连接失败",

                            icon: "error",

                            mask: true,

                        });

                        _that.isConnectIng = false

                

                    }

               

                });

            } catch (error) {

                // console.log(error, 'onBLECharacteristic');

                uni.hideLoading()

                modal.toast('监听notify失败')

                throw error

            }

        },

        //--------------------------------step12end----------------------

        // 获取要写入蓝牙设备的值

        writeBLECharacteristic(val) {

            let _that = this;

            let buffer = _that.string2ArrayBuffer(val);

            try {

                wx.writeBLECharacteristicValue({

                    deviceId: _that.deviceId,

                    serviceId: _that.serviceId,

                    characteristicId: _that.characteristicId,

                    value: buffer,

                    // writeType: "write",

                    success: function (res) {

            

           

                  

                    },

                    fail: function (err) {

                        uni.hideLoading()

                        if (_that.showLoading) _that.showLoading = false

                        modal.toast("写入数据失败");

                        if (_that.$refs["paging"]) {

                            _that.$refs["paging"].scrollToTop();

                            _that.$refs["paging"].complete();

                        }

                    },

                });

            } catch (error) {

                uni.hideLoading()

                modal.toast("写入数据失败");

                if (_that.showLoading) _that.showLoading = false;

                throw error

            }

        },

        async stopBluetooth() {

            let _that = this

            try {

                wx.stopBluetoothDevicesDiscovery({

                    success: (result) => {

                        if (_that.$refs["paging"]) {

                            _that.$refs['paging'].scrollToTop()

                            _that.$refs["paging"].complete()

                        }

                    },

                    fail: (error) => {

                        console.log("停止搜寻附近的蓝牙外围设备失败", error);

                    },

                });

            } catch (error) {

                // console.log('stopBluetooth', error);

                throw error


            }


        },

        // 字符串转ArrayBuffer

        string2ArrayBuffer(str) {

            try {

                var bytes = new Array();

                var len, c;

                len = str.length;

                for (var i = 0; i < len; i++) {

                    c = str.charCodeAt(i);

                    if (c >= 0x010000 && c <= 0x10ffff) {

                        bytes.push(((c >> 18) & 0x07) | 0xf0);

                        bytes.push(((c >> 12) & 0x3f) | 0x80);

                        bytes.push(((c >> 6) & 0x3f) | 0x80);

                        bytes.push((c & 0x3f) | 0x80);

                    } else if (c >= 0x000800 && c <= 0x00ffff) {

                        bytes.push(((c >> 12) & 0x0f) | 0xe0);

                        bytes.push(((c >> 6) & 0x3f) | 0x80);

                        bytes.push((c & 0x3f) | 0x80);

                    } else if (c >= 0x000080 && c <= 0x0007ff) {

                        bytes.push(((c >> 6) & 0x1f) | 0xc0);

                        bytes.push((c & 0x3f) | 0x80);

                    } else {

                        bytes.push(c & 0xff);

                    }

                }

                var array = new Int8Array(bytes.length);

                for (var i in bytes) {

                    array[i] = bytes[i];

                }

                return array.buffer;

            } catch (error) {

                uni.hideLoading()

                modal.toast('解析ArrayBuffer失败~')

                // console.log(error, 'string2ArrayBuffer');


                throw error

            }

        },

        //ArrayBuffer 转字符串

        str2ab(arrayBuffer) {

            try {

                let unit8Arr = new Uint8Array(arrayBuffer);

                let encodedString = String.fromCharCode.apply(null, unit8Arr);

                let decodedString = decodeURIComponent(escape(encodedString)); //没有这一步中文会乱码

                return decodedString;

            } catch (error) {

                //抛出异常不管了

                // console.log(error, 'str2ab');

                uni.hideLoading()

                modal.toast('解析数据失败~str2ab')

                return false;

            }

        },

        hex2ab(str) {

            try {

                return String.fromCharCode.apply(null, new Uint8Array(str));

            } catch (error) {

                uni.hideLoading()

                modal.toast('解析数据失败~hex2ab')

                // console.log(error, 'hex2ab');

                throw error

            }

        },

        //16进制ArrayBuffer 转字符串 不去掉 \n

        str2abEmpty(arrayBuffer) {

            try {

                let str = String.fromCharCode.apply(null, new Uint8Array(arrayBuffer));

                let ret = str.replace(/\n/g, "/n"); //将\n标记为/n

                return ret;

            } catch (error) {

                uni.hideLoading()

                modal.toast('解析数据失败~')

                throw error

            }

        },

        // 16进制(byte格式)转字符串

        hexToString(str) {

            try {

                let res = str.replace(/\\x/g, "%");

                let result = decodeURIComponent(res, "utf-8");

                return result;

            } catch (error) {

                uni.hideLoading()

                modal.toast('解析WiFi数据失败')

                setTimeout(() => {

                    this.currentIndex = 0

                }, 1000);

                this.$store.commit('submitErrorLog', {

                    error_type: "handlerError",

                    url: 'bluebooth.hexToString',

                    param: { wifiListStr: this.wifiListStr },

                    timeout: '0',

                    epukey: skeyTool.getSkey(),

                    datetime: utils.formatTime(new Date()),

                    err_code: '200'

                })

                throw error

            }

        },

        async closeBlueTooth() {

            try {

                if (this.connectFlag) {

                    wx.closeBLEConnection({

                        deviceId: this.deviceId,

                        success(res) {

                            console.log('closeBLEConnection', res);

                        },

                        fail(err) {

                            console.log(err, 'closeBlueTooth', 'fail')

                        },

                    })

                }

            } catch (error) {

                throw error

            }

        },

        watchBleConnectionState() {

            try {

                wx.onBLEConnectionStateChange((res) => {

                    if (!res?.connected) {

                        uni.hideLoading()

                        modal.toast('设备已断开蓝牙连接')

                    }

                })

            } catch (error) {

                throw error

            }

        },

        //清空倒计时、重置蓝牙功能相关数据配置

        //关闭蓝牙相关操作

        handlerCloese() {

            //关闭蓝牙模块。

            wx.closeBluetoothAdapter({

                success: (res) => {

                    console.log('closeBluetoothAdapter', res);


                },

                fail: (err) => {

                    console.log('closeBluetoothAdapter', err);

                }

            });

            // 移除搜索到新设备的事件的全部监听函数

            uni.hideLoading();

            uni.hideToast();

        }

    },

    beforeDestroy() {

        this.handlerCloese()

    },

    //针对蓝牙打开手机自带蓝牙设置页面 返回到当前页面 特殊处理

    onShow() {

        setTimeout(() => {

            if (this.isOpenSetting) this.getBluetoothAdapter()

        }, 500)

    },


    computed: {

        ...mapState(["privacyFlag", 'needPrivacy']),

    },

}

安卓端、iOS端 多次写入数据wx.writeBLECharacteristicValue 偶现wx.onBLECharacteristicValueChange无回调 有时候收到第一条数据后后面无回调 有时候是接收到了硬件方发送的一半数据 硬件方始终是20字节 我这边也没有超过20字节 这里的wifiListStr我会在设备端发送给我sendWifiListOK之后重新解析一遍 当前这个代码是当做一个mixins使用的 frequency signal 是硬件发送的自定义数据(第一条数据),后面就没执行了也没报错 返回上个页面关闭了蓝牙适配器

最后一次编辑于  09-10
回答关注问题邀请回答
收藏

1 个回答

  • 禾伙人@豆
    禾伙人@豆
    1天前

    解决了吗

    1天前
    有用
    回复
登录 后发表内容