微信小程序蓝牙BLE开发实战——遇到问题及踩坑(三)

微信小程序蓝牙BLE开发实战(三)

对于我这种小白,遇到问题是常见的哈。这里记录下,避免日后再踩坑

1. iPhone6及6plus无法搜索到设备?

特别注意: wx.onBluetoothDeviceFoundAPI返回的数据结构, 其中advertisData数据段。来看下res.devices 的结构。 有些供应商设备是没有返回的。

返回的数据结构图:

下图是不同设备上返回的数据。明显看到左图有返回advertisData数据段, 右图则没有

说明: advertisData在没有数据返回情况下,Android设备会返回{}IOS设备直接不返回这个字段。
在这里插入图片描述

复现:

当广播数据中没有advertisData数据段情况下, 代码中获取时,除了真机调试下正常运行, 其他的预览模式、体验版及线上运行均有问题

// 转换后,根据协议文档取需要数据(advertisData不一定有数据)

var hexStr = ab2hex(device.advertisData);
console.log("广播数据中转换后:advertisData---->" + hexStr);

解决方案:

注意:advertisData数据段,返回是ArrayBuffer类型。 使用时需转换

if (device.advertisData != null) { //判断对象是否为null,advertisData不一定有
    var hexStr = ab2hex(device.advertisData);
    console.log("广播数据中转换后:advertisData---->" + hexStr);
}


// ArrayBuffer转16进度字符串示例
function ab2hex(buffer) {
    var hexArr = Array.prototype.map.call(
        new Uint8Array(buffer),
        function(bit) {
            return ('00' + bit.toString(16)).slice(-2)
        }
    )
    return hexArr.join('');
}

ps: 当时第一次接触微信小程序BLE, 项目上线发现此问题。那时项目中对接多个供应商有些没有返回advertisData数据段, 忘加判断语句。【细节很重要】

记得那个周末休息慢慢排查解决的。

2. IOS无法获取mac地址,如何连接设备呢?

再一次的了解 wx.onBluetoothDeviceFoundAPI返回的数据结构。主要关注deviceId数据

注意: deviceId

  1. Android设备中的deviceId得到是mac地址
  2. IOS设备中的deviceId得到是UUID, 而且是动态的。

返回数据效果图:

在这里插入图片描述

解决方案:

  • 通过广播数据段advertisData中获取需要的mac地址。【注意 有些供应商设备是没有返回的】

  • 通过广播数据段namelocalName中通过名称匹配设备。【有些供应商直接把mac地址拼接到name中】

    1. 如上图: 关注下name返回的格式, 通常供应商以: 前缀+mac(供应商缩写+设备mac
    2. 格式都可以更改的, 根据需求和硬件硬件部商量
    // 例如:advertisData字段返回数据是0000365544332211a7d4...,可根据文档说明取需要数据
    let data = '0000365544332211a7d4'; 
    let subMac = data.subString(4, 16); //例取365544332211为mac
    

3. Android二次连接搜索不到设备?

注意: 操作完成后一定要断开设备连接释放蓝牙模块。否则再次连接会出现搜索不到设备,需关闭小程序再次搜索才可以,IOS不受影响

wx.closeBLEConnection(Object object)

wx.closeBluetoothAdapter(Object object)

原因:
wx.onBluetoothDeviceFound接口返回的是新的蓝牙设备,之前连接过的在部分安卓机型上,不算是新的蓝牙设备,所以会出现二次连接搜索不到设备。

解决方案:

function closeBLEConnection() {
    console.log("断开与低功耗蓝牙设备的连接。", deviceId);

    if (deviceId) {
        wx.closeBLEConnection({
            deviceId: deviceId,
            success: function(res) {
                console.log("closeBLEConnection。success", res);

            },
            fail: function(res) {
                console.log("closeBLEConnection。fail", res);
            },
            complete: function() {
                status = false;
            }
        })

        wx.closeBluetoothAdapter({
            success: function(res) {
                console.log("closeBluetoothAdapter ==>res:", res);
            },
            fail: function(error) {
                console.log("closeBluetoothAdapter ==>error:", error);
            }
        })
    }

    _discoveryStarted = false;
    isnotExist = true;
    _deviceId = '';
    deviceId = '';
}

4. 发送数据过程中易出现写入失败

注意: 开启notify建议不要马上发送指令,否则易出现写入失败

解决方案:

  • wx.writeBLECharacteristicValue向设备写入数据时,添加setTimeout()延迟1秒左右的动作。
function writeData(hex) {
    setTimeout(() => {
        //类型转换
        var enDataBuf = new Uint8Array(hex);
        var buffer1 = enDataBuf.buffer

        wx.writeBLECharacteristicValue({
            deviceId: _deviceId,
            serviceId: _serviceId,
            characteristicId: _characteristicId,
            value: buffer1,
            success: (res) => {
                wx.hideLoading();
                console.log("写数据返回结果", res.errMsg);
            },
            fail(res) {
                console.log("写数据失败..", res);
                asddErrorCallback(res.errCode, "");
            }
        })
    }, 1000)
}

5. 什么版本能支持蓝牙功能?

iOS微信客户端 6.5.6版本开始支持Android 6.5.7 版本开始支持因此项目中需要做好版本检测

蓝牙说明

解决方案:

  • 第一步:app.jsonLaunch()方法中,获取系统信息接口
//获取系统信息
this.globalData.sysinfo = wx.getSystemInfoSync();
  • 第二步: 得到versionsystemplatform等需要的相关信息。
getVersion: function() { //获取微信版本号
    return this.globalData.sysinfo["version"]
},
getSystem: function() { //获取操作系统版本
    return this.globalData.sysinfo["system"]
},
getPlatform: function() { //获取客户端平台
    return this.globalData.sysinfo["platform"]
},
  • 第三步: 在需要检测版本页面,通常在首页对应的.js中,判断版本是否支持蓝牙API。

    这里放在单独.js文件中, 在index.js中引入并使用。

    A: 新建checkVersion.js

    const app = getApp()
    
    /**
     * 版本比较
     */
    function versionCompare (ver1, ver2) { //版本比较
        // console.log("ver1" + ver1 + 'ver2' + ver2);
        var version1pre = parseFloat(ver1)
        var version2pre = parseFloat(ver2)
        var version1next = parseInt(ver1.replace(version1pre + ".", ""))
        var version2next = parseInt(ver2.replace(version2pre + ".", ""))
        if (version1pre > version2pre)
            return true
        else if (version1pre < version2pre)
            return false
        else {
            if (version1next > version2next)
                return true
            else
                return false
        }
    }
    
    
    /**
     * 微信版本检测
     * Android从微信 6.5.7 开始支持,iOS从微信 6.5.6 开始支持
     */
    function checkWechatVersion() {
        if (app.getPlatform() == 'android' && versionCompare('6.5.7', app.getVersion())) {
            wx.showModal({
                title: '提示',
                content: '当前微信版本过低,请更新至最新版本体验',
                showCancel: false
            })
        }else if (app.getPlatform() == 'ios' && versionCompare('6.5.6', app.getVersion())) {
            wx.showModal({
                title: '提示',
                content: '当前微信版本过低,请更新至最新版本体验',
                showCancel: false
            })
        }
    }
    
    
    //导出
    module.exports = {
        checkWechatVersion: checkWechatVersion
    }
    

    B:index.jsonLoad()方法中使用

    var checkVersion = require('../../../utils/checkVersion.js');
    
    onLoad: function(options) {
        // 检测版本
        checkVersion.checkWechatVersion();
    }
    

wx.getSystemInfoSync()返回的数据效果图

在这里插入图片描述

版本比较参考大神们

6. 安卓 6.0 及以上设备需打开定位服务?

  • 在测试过程中,发现Android 6.0及以上系统的一些设备, 无法搜索蓝牙设备, 因此建议在项目中提示用户打开微信定位服务(GPS)

  • 打开权限: 设置—>应用程序—>找到已安装微信应用—>权限—>打开定位

解决方案:

这里写简单提示,实际上还可以引导用户打开授权位置,有空再更新下

isOpenLocation: function() {
    let that = this;
    //判断提示安卓系统6.0及以上需打开定位服务
    if (app.getPlatform() == 'android' && app.getSystem() >= 'Android 6.0') {
        wx.getSystemInfo({
            success(res) {
                // console.log("获取系统信息", res);
                if (!res.locationAuthorized && res.locationAuthorized != undefined) {
                    wx.showModal({
                        title: '提示',
                        content: '为了更好体验测量,\r\n请您打开微信允许授权定位',
                        showCancel: false
                    })
                } else {
                    that.scanCode();
                }
            }
        })
    } else {
        that.scanCode();
    }
},

7. 写入数据大于20字节,如何发送数据?

注意:

  • 并行调用多次会存在写失败的可能性。
  • 小程序不会写入数据包大小限制,但系统与蓝牙设备限制蓝牙4.0单次传输的数据大小,超过最大字节数后会发生写入错误建议每次写入不超过20字节
  • 若单次写入数据过长,iOS 上存在系统不会有任何回调的情况(包括错误回调)

解决方案:

分包发送:

系统与蓝牙单次传输只能发送20个字节, 因此大于20个字节时需要手动分包发送

说明:写入数据时,需要延迟,否则易出现写入失败【可查看:第4个案例】

var hex = [0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x50, 0x51, 0x52]; //22个字节

if (hex.length > 20) {
    var result = this.split_array(hex, 20);
    console.log('分包后的数组', result);
    writeData(result[0]); //写入第一条数据
    setTimeout(() => {
        writeData(result[1]); //写入第二条数据
    }, 5)
} else {
    console.log('小于20字节写入数据');
    writeData(hex);
}

/**
* 将一个数组分割两个
*/
split_array: function(arr, len) {
    var a_len = arr.length;
    var result = [];
    for (var i = 0; i < a_len; i += len) {
        result.push(arr.slice(i, i + len));
    }
    return result;
},

8. 大于255字节如何处理?

注意:一个字节:最大整数是255

例: 控制时间指令为: [0xa1, 0x30, 0x00, 自定义时间n]
1. 发送时间30秒,即[0x0a, 0x30, 0x00, 0x1e]
2. 假设: 900秒,如何发送指令呢?
【难道是这样发送数据:[0x0a, 0x30, 0x00, 0x384] 正常是不可以的。】

解决方案:

拆分为两个字节,当不足位数前面补0关于进制转换请查看

  • 假设: 900 转16进制后为 384, 那么我们把他拆分为两个字节发送就可以了。 即 0x03, 0x84
let n = 900;	
n = n.toString(16);  // 将900转化为16进制数(以字符串显示)
var s = "00000000" + n;
s = s.substr(n.length, s.length); // 截取最后8位字符
let str1 = s.substring(4, 6);
str1 = '0x' + str1; //同等: str1 = str1.toString(16); 无需拼0x
let str2 = s.substring(6, 8);
str2 = str2.toString(16);;

var nS = parseInt(str1, 16) //字符串转16进制
var nE = parseInt(str2, 16)

var hex = [0xa1, 0x30, nS, nE];
writeData(hex);	 //写入数据

9. 如何把设备返回的随机码作为加密的key

说明:

  • 每次连接上设备时,设备会第一时间返回随机码(长度不固定),例如: 格式为KEY+随机码

  • 获取随机码生成加密的key

解决方案:

//Eg: KEY8as6 (其中8as6为随机码)

//第一步:把设备返回的数据进行转换
var resValue = new Uint8Array(res.value, 0);
//第二步: 把Uint8Array转换为字符
var tmp = String.fromCharCode.apply(String, resValue);
//判断是否包含KEY
if(tmp.indexOf('KEY') != -1) {
    //获取加密key
    getEnKey(resValue);
}


/**
 * 获取加密key
 */
function getEnKey(resValue) {
    var sliceStr = resValue.subarray(3);
    console.log("截取key后的值是:", sliceStr); //得到随机码 8as6

    //假设加密的key为:0123456789ABCDEF
    var key = [0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46];
    var cryptoKey = new Uint8Array(key);
    for (var i = 0; i < sliceStr.length; i++) {
        cryptoKey[i] = sliceStr[i];
    }
    enKEY = cryptoKey;
}

//最后加密的key为: 8as6456789ABCDEF

BLE项目实战下载

查看实战案例

蓝牙BLE项目实战

关于下篇内容

  • 在开发蓝牙BLE应用一些进制转换
  • 8
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值