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

2023-11-01

微信小程序蓝牙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应用一些进制转换
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • 【matlab】中取矩阵的某一行某一列

    1 操作指令 取某一行 Ki K i 取某一列 Kj K j 取某几行 Kij K i j 取某几列 Kij K i j i和j表示行数和列数 2 举例分析 例如矩阵K 1 2 3 4 5 6 7 8 9 三行三列 K 1 2 3 4 5
  • 【C语言】指针题及解析

    需要云服务器等云产品来学习Linux的同学可以移步 gt 腾讯云 lt gt 阿里云 lt gt 华为云 lt 官网 轻量型云服务器低至112元 年 新用户首次下单享超低折扣 例一 需要考虑大小端问题 该例仅限32位平台 小端存储模式 in
  • requests.post()提取返回数据中的具体某个数值

    返回json数据是这样的 提取返回code rsp requests post url data jsonData headers headers timeout 3 json code rsp code if code 1000 prin
  • VRF配置

    SW 2既作为集团核心交换机 同时又使用相关技术将SW 2模拟为Internet交换机 实现集团内部业务路由表与Internet路由表隔离 那位大神能教教我这道题目要怎么做啊 转载于 https blog 51cto com 1432192
  • iOS开发之网络监听(二)SCNetworkReachability

    文章目录 判断当前网络是否可达 第一个参数 SCNetworkReachabilityRef类型的target 第二个参数 SCNetworkReachabilityFlags类型的flags SCNetworkReachability是S

随机推荐

  • 一个基于@DS动态数据库的Java远程数据库同步程序

    同步程序开发文档 一 开发目标 本程序为一同步程序 DAO层连接2个数据库 远程直连一个orcal数据库 读取数据后存入本地的mogdb数据库 两个数据库访问通过 DS 动态数据库切换 通过定时任务调用同步类 并保存同步日志到数据库 二 程
  • React Antd 前端生成cron表达式

    不知道你在玩游戏的时候是否发现过以下情况 1 玩某些游戏的时候 发现他的排行榜并不是时时更新的 而是每半个小时 或者一个小时更新一次 2 又比如很火的王者荣耀手游 它的日常任务 都是每天5点进行更新 那么 这些时间控制 到底是由谁控制得如此
  • 拼接json和数组

    function form2Json id var arr id serializeArray var jsonStr jsonStr for var i 0 i lt arr length i jsonStr arr i name arr
  • 如何做代码评审(code review)

    1 定义 Code Review 即日常所说的代码评审或代码回顾 主要是在软件开发的过程中 对功能源代码进行评审 其目的是找出并修正软件开发过程中出现的错误的过程 提高和改进代码质量的过程 2 目的 2 1 提前发现缺陷 code revi
  • 电阻的固有噪声(热噪声)

    电阻的固有噪声是指其自身产生的噪声 包括热噪声和过剩噪声 热噪声亦称白噪声 是由导体中电子的热震动引起的 它存在于所有电子器件和传输介质中 它是温度变化的结果 但不受频率变化的影响 热噪声是在所有频谱中以相同的形态分布 它是不能够消除的 由
  • css怎么跟html搞一起,css和html的四种结合方式

    1 在每个HTML标签上面都有一个属性 style 把css和HTML结合在一起 我是一只小小鸟 2 使用HTML的一个标签实现 css代码 div background color red color gray 3 在style标签里面
  • Java实现多线程下载文件

    这是本人在实际开发当中遇到的多线程下载文件并记录下来 public class DownloadUtil private String pathFile private String strFile private DownloadThre
  • 关于java中的泛型 T 和 ?的区别(转载+改动)

    T表示泛型 new的时候要加入泛型 更方便通用 表示不确定的类型 一般用在通配 Object表示java中所有类的父类 在集合中使用时要格外注意 jdk为了便于理解 用K表示键 V表示值 T表示type类型 E表示enum枚举 其实这四个都
  • 飞链云元宇宙、区块链、3D数字艺术品、AI绘画共创数字新生态

    2022 飞链云生态 飞链云元宇宙 区块链 3D数字艺术品 AI绘画共创数字新生态 本文地址 https feilianyun yuque com books share c2d90a1b 6bba 4d23 9fb8 65a011cf3a
  • SpringBoot解析json文件

    SpringBoot解析json文件 第一步 要有一个自定义的json文件 例如 文件名 user json username 张三 userage 20 username 莉莉 userage 18 第二步 要有一个实体类 例如 Data
  • linux vscode 基于 configurationProvider 设置提供的信息检测到 #include 错误

    代码正常 vscode经常性会出现include报错 大多数并不是includepath设置错误的原因 困扰了我好几天 结合大家的提示终于解决了问题 现在把方法分享给大家 希望对大家有帮助 解决办法 1 在命令行执行 gcc v E x c
  • Django 创建第一个web项目

    版本说明 python 3 7 0 django 3 0 6 Django 管理工具 django admin 部署虚拟环境 安装virtualenv pip install virtualenv i https mirrors aliyu
  • 开源技术选型手册 (china-pub 首发) -目 录

    第1章c闲话开源社区篇cc 第2章cWeb框架篇cc 2 1cStrutsc 2 2cSpringc 2 3cSeamcc 第3章c开源Web服务器c 3 1cApachecc 3 2cLighttpdcc 3 3cNginxc 第4章c应
  • 【MySQL】varchar转int类型的方法

    MySQL varchar转int类型的方法 CAST函数的使用 1 问题描述 获取一个表user中age的最大值 由于历史原因 age是varchar类型的 2 问题解决 方案一 select max cast sex as UNSIGN
  • Blender辅助工具集:M3插件

    1 MACHIN3tools M3 插件 一个辅助工具集 MACHIN3tools An Addon to Streamline Blender 3 3 and beyond by machin3 io https github com m
  • Spring(DI)

    DI Dependency Injection 即依赖注入 对象之间的依赖由容器在运行期决定 即容器动态的将某个依赖注入到对象自重 基于XML配置注入依赖 有参构造函数注入依赖 bean类实现有参构造函数 public class Stud
  • 开始在CSDN上安家了哈!

    2014年计划完成50 原创blog 这是我的目标
  • vue项目打包部署到tomcat(详细)

    hash路由模式打包部署到tomcat 1 修改config index js文件下的assetsPublicPath为 2 修改router文件夹下index js添加 base 文件夹名称 例如 yuncheng 可以自己随意设置 3
  • 未找到 van-toast 节点,请确认 selector 及 context 是否正确

    1 json文件引入 van toast vant weapp toast index 2 js文件引入 import Toast from vant weapp toast toast 3 wxml写入
  • 微信小程序蓝牙BLE开发实战——遇到问题及踩坑(三)

    微信小程序蓝牙BLE开发实战 三 对于我这种小白 遇到问题是常见的哈 这里记录下 避免日后再踩坑 文章目录 微信小程序蓝牙BLE开发实战 三 1 iPhone6及6plus无法搜索到设备 解决方案 2 IOS无法获取 mac 地址 如何连接