微信小程序开发

您所在的位置:网站首页 安卓手机蓝牙和ipad蓝牙传输失败 微信小程序开发

微信小程序开发

2023-09-24 23:14| 来源: 网络整理| 查看: 265

最近随项目接触了下小程序的BLE开发。体会颇多。

小程序BLE开发前的准备操作:

    1、熟读小程序开发文档,文档链接。

    2、微信开发者工具。

    3、对应的BLE蓝牙设备,我们需要对BLE设备进行读写操作。

一、小程序BLE开发API简介

微信小程序目前有蓝牙 API 共 18 个,其中操作蓝牙适配器的共有 4 个,分别是

wx.openBluetoothAdapter 初始化蓝牙适配器 wx.closeBluetoothAdapter 关闭蓝牙模块 wx.getBluetoothAdapterState 获取本机蓝牙适配器状态 wx.onBluetoothAdapterStateChange 监听蓝牙适配器状态变化事件

其中,扫描和获取周围BLE设备的有4个(这4个操作方式与普通蓝牙一样):

wx.startBluetoothDevicesDiscovery 开始搜寻附近的蓝牙外围设备 wx.stopBluetoothDevicesDiscovery 停止搜寻附近的蓝牙外围设备 wx.getBluetoothDevices 获取所有已发现的蓝牙设备 wx.onBluetoothDeviceFound 监听寻找到新设备的事件

连接BLE设备的2个:

wx.createBLEConnection 连接低功耗蓝牙设备 wx.closeBLEConnection 断开与低功耗蓝牙设备的连接

连接成功后,读写BLE对应特征对象的数据:

wx.getConnectedBluetoothDevices 根据 uuid 获取处于已连接状态的设备 wx.getBLEDeviceServices 获取蓝牙设备所有 service(服务) wx.getBLEDeviceCharacteristics 获取蓝牙设备所有 characteristic(特征值) wx.readBLECharacteristicValue 读取低功耗蓝牙设备的特征值的二进制数据值 wx.writeBLECharacteristicValue 向低功耗蓝牙设备特征值中写入二进制数据 wx.notifyBLECharacteristicValueChange 启用低功耗蓝牙设备特征值变化时的 notify 功能 wx.onBLECharacteristicValueChange 监听低功耗蓝牙设备的特征值变化 wx.onBLEConnectionStateChange 监听低功耗蓝牙连接的错误事件

二、微信小程序开发前需要注意的事项

android微信支持BLE蓝牙的微信版本为:6.5.7;

android 6.0 以上的手机未打开系统定位服务时,搜索不到蓝牙设备;

ios微信支持BLE蓝牙的微信版本为:6.5.6。

所以做BLE蓝牙开发,为了提高用户的小程序体验感,需要对用户使用的微信版本以及android版本进行判断,并做合理的解决方式。

下面是获取手机当前微信版本和手机系统版本的封装方法,将方法放入apps.js全局js文件中:

onLaunch: function() { this.globalData.sysinfo = wx.getSystemInfoSync() }, getModel: function () { //获取手机型号 return this.globalData.sysinfo["model"] }, getVersion: function () { //获取微信版本号 return this.globalData.sysinfo["version"] }, getSystem: function () { //获取操作系统版本 return this.globalData.sysinfo["system"] }, getPlatform: function () { //获取客户端平台 return this.globalData.sysinfo["platform"] }, getSDKVersion: function () { //获取客户端基础库版本 return this.globalData.sysinfo["SDKVersion"] }

为了对手机微信版本和系统版本做比较,封装有一个版本比较的方法

versionCompare: function (ver1, 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 } }

所以,在实际的操作中,比如点击了按钮需要调用手机系统蓝牙去扫描操作之前,需要校验以上的各项参数。整体代码:

//判断系统版本、微信版本、定位服务等权限和信息 function checkPhoneInfo(obj){ //Android 从微信 6.5.7 开始支持,iOS 从微信 6.5.6 开始支持 //第一项,如果手机是android系统,需要判断版本信息 if (apps.getPlatform() == "android" && versionCompare("6.5.7", apps.getVersion())) { wx.showModal({ title: '提示', content: '当前微信版本过低,请更新至最新版本', showCancel: false }); obj.setData({ btnDisabled: false, }); //执行quit机制 quit(obj); return; } //第二项,如果手机是ios系统,需要判断版本信息 if (apps.getPlatform() == "ios" && versionCompare("6.5.6", apps.getVersion())) { wx.showModal({ title: '提示', content: '当前微信版本过低,请更新至最新版本', showCancel: false }); obj.setData({ btnDisabled: false, }); //执行quit机制 quit(obj); return; } //版本 以及 平台校验完毕后 需要判断蓝牙的相关信息 //微信小程序 android6.0手机需要开启位置服务,否则扫描不到设备 console.log("当前系统版本:" + apps.getSystem());//Android 8.1.0 console.log("当前微信版本:" + apps.getVersion()); if (apps.getPlatform() == "android") { console.log("android手机 当前系统版本号:" + apps.getSystem().replace("Android", "").replace(" ", "")); //android版本高于6.0.0 if (!versionCompare("6.0.0", apps.getSystem().replace("Android","").replace(" ",""))) { console.log("当前系统版本高于6.0.0"); //位置服务权限 wx.getSetting({ success: function (res) { var statu = res.authSetting; //位置服务授权校验操作 if (!statu['scope.userLocation']) { wx.showModal({ title: '温馨提示', content: '请授予位置服务权限,以便更好的搜索周围设备', success: function (tip) { if (tip.confirm) { //点击确认 开始判断位置服务权限信息 wx.openSetting({ success: function (data) { if (data.authSetting["scope.userLocation"] === true) { wx.showToast({ title: '授权成功', icon: 'success', duration: 1000 }) //授权成功之后,调用自己封装的蓝牙各项操作 bleOperateFun(obj); } else { wx.showToast({ title: '授权失败', icon: 'none', duration: 1000 }); obj.setData({ btnDisabled: false, }); //执行quit机制 quit(obj); } } }) }else{ console.log("点击了取消操作"); obj.setData({ btnDisabled: false, }); //执行quit机制 quit(obj); } } }) }else { //存在权限,调用封装的蓝牙方式继续进行 bleOperateFun(obj); } }, fail: function (res) { wx.showToast({ title: '调用授权窗口失败', icon: 'success', duration: 1000 }); obj.setData({ btnDisabled: false, }); //执行quit机制 quit(obj); } }) } else if (!versionCompare(apps.getSystem().replace("Android", "").replace(" ", "")), "4.3.0") { //系统版本低于4.3的,使用不了ble蓝牙 wx.showModal({ title: '温馨提示', content: '您的手机系统版本较低,无法操作BLE蓝牙设备', showCancel:false, }); obj.setData({ btnDisabled: false, }); //执行quit机制 quit(obj); }else { console.log("系统版本低于6.0.0但高于4.3.0"); //除去android系统的手机(由于最开始过滤了能支持蓝牙的最低微信版本 所以此处无需再判断) bleOperateFun(obj); } } //除android以外的ios或者其他系统 bleOperateFun(obj); }

三、BLE蓝牙开发,开启当前手机ble蓝牙适配器,注册相关的监听事件

function bleOperateFun(obj){ //1、判断手机蓝牙是否开启 wx.openBluetoothAdapter({ success: function(res) { console.log("初始化蓝牙适配器成功"); //1、开启蓝牙适配器的状态变化监听 wx.onBluetoothAdapterStateChange(function(res){ console.log("蓝牙适配器状态变化",res); }); //2、开启搜索周围设备的情况监听事件 (扫描 开锁 两次按钮点击 针对同一个设备只执行了一次) wx.onBluetoothDeviceFound(function(res){ console.log("扫描周围设备详情返回:"+JSON.stringify(res)); //判断是否为 "创想物联" 的设备 若是则需要进行连接操作和关闭扫描操作(节省手机资源) res.devices.forEach(device=>{ console.log(device.name +"/"+device.localName); console.log("广播数据:" + apps.ab2hex(device.advertisData)); }); }); // 3、连接状态变化监听 --监听低功耗蓝牙连接状态的改变事件。包括开发者主动连接或断开连接,设备丢失,连接异常断开等等 wx.onBLEConnectionStateChange(function(res){ console.log("蓝牙设备连接状态监听回调:\n"+JSON.stringify(res)); }); // 4、读取特征值数据监听事件 ---- wx.readBLECharacteristicValue(Object object)调用后,若要取得其中的数据,需要再此回调中获取 wx.onBLECharacteristicValueChange(function(res){ console.log("wx.onBLECharacteristicValueChange 监听事件:\n"+JSON.stringify(res)); }) //开启扫描周围设备模式 startScanAroundDevice(obj); }, fail:function(res){ console.log("初始化蓝牙适配器失败") wx.showModal({ title: '温馨提示', content: '请检查手机蓝牙是否打开', showCancel:false, }); obj.setData({ btnDisabled: false, }); //执行quit机制 quit(obj); } }) }

在开启扫描操作后,会触发设置好的 wx.onBluetoothDeviceFound 回调函数,当发现了设备,则会显示设备的mac,uuid,广播数据等。这里有一个重点:

获取广播数据,小程序中读取 BLE 广播数据使用 wx.onBluetoothDeviceFound 接口中的 advertisData,对应上面兼容问题的 devices 格式,如 devices.advertisData,这个数据是 ArrayBuffer类型的数据,如果需要显示至日志中,需要对其进行相关的转换处理操作,使用如下代码:

//广播数据为Array Buffer类型 ArrayBuffer转16进度字符 ab2hex: function(buffer) { var hexArr = Array.prototype.map.call( new Uint8Array(buffer), function(bit) { return ('00' + bit.toString(16)).slice(-2) } ) return hexArr.join(''); },

四、小程序BLE开发,扫描到指定设备后,需要对其进行连接操作

      连接成功后,为了节省手机端的资源,需要对扫描进行关闭处理。(假设设置扫描开始,10秒后会有关闭操作流程;但可能在2秒的时候已经扫描到指定设备,我们知道,扫描操作及其耗电,所以为了避免过多的资源浪费,需要提前进行关闭操作)。

五、读写操作

    1、按照微信提供的api,可以进行读写操作,读操作成功后会触发之前(二)中的设置监听事件  wx.onBLECharacteristicValueChange ,而写操作只有成功和失败两种回调。

    2、写操作的api为

wx.writeBLECharacteristicValue({ deviceId: obj.data.lockMac, serviceId: apps.bleProperties.bleServiceUUID, characteristicId: apps.bleProperties.writeCharacUUID, value: sendValue, success: function(res) { console.log("发送开锁命令成功回调:\n"+JSON.stringify(res)); }, fail(res){ console.log("写数据失败回调"+res); wx.showModal({ title: '温馨提示', content: '发送开锁命令失败!', showCancel:false, }) quit(obj); } })

其中的各项参数在api文档中都有充分的介绍,这里不说其他废话,但其中的 value 属性为 ArrayBuffer 类型,所以需要进行数据格式的转换操作

strToArrayBuffer:function(aes,str){ //首先将str转化为数组 var strtoHexArray = aes.hex_to_bytes(str); //取一半数据的长度作为arraybuffer的长度 var buffer = new ArrayBuffer(str.length >> 1); var bufView = new DataView(buffer); //保存数据至arraybuffer中 for(var i = 0,len = (str.length >> 1);i> 1); for (var i = 0; i < len; i += 2) { bytes[i >> 1] = parseInt(str.substr(i, 2), 16); } return bytes; }

六、断开连接需要释放资源

很多时候开发测试,断开连接后,再次扫描设备时,可能出现一堆问题。

开发的原则是开启了资源,在使用完成后需要释放相关资源信息。所以在断开操作中,需要使用释放手机蓝牙端资源。

function quit(obj) { //如果连接上了 需要断开连接操作 if (isConnected) { wx.closeBLEConnection({ deviceId: obj.data.lockMac, success(res) { console.log("quit() 断开连接操作成功回调"); isConnected = false; }, fail(res) { console.log("quit() 断开连接操作失败回调"); } }); } //如果扫描操作执行了的 需要释放手机蓝牙的资源 if (isStartScan) { wx.closeBluetoothAdapter({ success: function(res) { console.log("quit wx.closeBluetoothAdapter 成功回调 清理手机蓝牙资源"); console.log(JSON.stringify(res)); }, fail(res) { console.log("清理手机端 蓝牙 资源失败回调 " + res); } }) } //不管操作进行到哪步 quit操作后 都需要释放按钮为 可点击状态 obj.setData({ btnDisabled: false, }); }

七、最后写操作中有几个潜在的重点

    1、BLE 4.0 中发送一个数据包只能包含 20 字节的数据,大于 20 字节只能分包发送。没做ios的测试(人穷用不起苹果),就拿android来说,每次最大发送20字节的数据,之前就说过了写操作没有可设置的回调,所以不需要操作过于麻烦。只需要在写入20字节成功之后,延迟一段时间(这个时间不好控制,我用的小米8测试设置200ms无压力,不同手机设置值肯定不同,需要找到一个合理的参数做为一个统一的处理),再进行下一个包的发送。

    2、当你扫描操作执行后,假如未扫描到设备,再次点击按钮进行扫描,即使有BLE设备在广播,也不会再扫描到设备。遇到这样的情况,需要释放手机端蓝牙的资源,代码如下(我的代码放于quit机制中):

//如果扫描操作执行了的 需要释放手机蓝牙的资源 if (isStartScan) { wx.closeBluetoothAdapter({ success: function (res) { console.log("quit wx.closeBluetoothAdapter 成功回调 清理手机蓝牙资源"); console.log(JSON.stringify(res)); }, fail(res) { console.log("清理手机端 蓝牙 资源失败回调 " + res); } }) }

   3、2019.03.04新增一个问题总结。android手机使用小程序的BLE模块,广播中的deviceId表示设备的mac信息,ios系统则是手机mac和设备mac加密产生的uuid值!连接设备也如此:安卓直接使用mac进行连接操作;但ios使用广播中读取到的UUID进行连接。

简单而言,全是扫描到设备后的deviceId信息

wx.onBluetoothDeviceFound(function (res) { console.log("扫描周围设备详情返回:" + JSON.stringify(res)); //判断是否为 "创想物联" 的设备 若是则需要进行连接操作和关闭扫描操作(节省手机资源) res.devices.forEach(device => { console.log(device.name + "/" + device.localName); }) }) obj.setData({ lockMac: device.deviceId,//2019.07.31在判断是当前设备后,使用扫描得到的deviceId进行连接操作(androd和ios) });

wx.createBLEConnection({ deviceId: obj.data.lockMac, success: function (res) { } })

    4、2019.03.05新增一个问题。Android手机使用小程序操作BLE设备,连接成功后可以直接进行特征数据的获取;但ios直接调用时,会出现10004的报错  官方文档报错信息连接。

如何解决ios手机使用小程序BLE报错问题。

只需要在连接成功和读设备特征数据之间,进行一项开启通信服务操作即可,按照java android开发ble规范来说,连接成功后是需要优先开启服务的,所以android和ios都统一开启服务!!

wx.createBLEConnection({ deviceId: obj.data.lockMac, success: function(res) { wx.hideLoading(); wx.showToast({ title: '连接成功', icon: 'success', duration: 1000 }) console.log("连接success回调:"+JSON.stringify(res)); //关闭扫描 stopScanAroundDevice(obj); //连接成功后 进行开锁流程操作(读 --- 写 -- 读) //判断是android还是ios(流程不同) if (apps.getPlatform() == "android"){ firstReadCharacVal(obj); return; } //ios wx.getBLEDeviceServices({ // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接 deviceId: obj.data.lockMac, success(res) { console.log(JSON.stringify(res)) console.log('device services:', res.services) console.log('device services:', apps.ab2hex(res)) console.log('device services:', apps.ab2hex(res.services)) //获取设备特征对象 wx.getBLEDeviceCharacteristics({ deviceId: obj.data.lockMac, serviceId: apps.bleProperties.bleServiceUUID, success: function(res) { console.log(JSON.stringify(res)) console.log("wx.getBLEDeviceCharacteristics ---->\n" + apps.ab2hex(res)); firstReadCharacVal(obj); }, fail:function(){ wx.showModal({ title: '温馨提示', content: '获取特征对象失败!', showCancel: false }); quit(obj); } }) }, fail:function(){ wx.showModal({ title: '温馨提示', content: '获取服务失败!', showCancel:false }); quit(obj); } }) }, fail: function (res) { wx.hideLoading(); wx.showToast({ title: '连接设备失败', icon: 'success', duration: 1000 }) console.log("连接设备失败") console.log("连接fail回调:"+res); obj.setData({ btnDisabled: false, }); //执行 quit 机制 quit(obj); } })

也就是说连接成功后,需要多进行一次wx.getBLEDeviceServices 和 wx.getBLEDeviceCharacteristics !!

八、2021.11.08 补充知识点

 1、如果进行了读写操作,在quit中需要释放资源,采取下列代码进行释放

if(isOpenCharacValueChange){ wx.offBLECharacteristicValueChange({ success: function(res) { console.log("quit wx.offBLECharacteristicValueChange 成功回调 清理手机蓝牙资源"); console.log(JSON.stringify(res)); }, fail(res) { console.log("wx.offBLECharacteristicValueChange 资源失败回调 " + res); } }) }

2、关于监听数据变化api

如果是监听指定的特征值对象数据变化监听,可以采取下列方式:

wx.onBLECharacteristicValueChange({ deviceId:obj.data.lockMac, characteristicId: apps.bleProperties.readCharacUUID, serviceId: apps.bleProperties.bleServiceUUID, success:function(res){ console.log("success--->wx.onBLECharacteristicValueChange :"+JSON.stringify(res)); isOpenCharacValueChange = true; }, fail:function(res){ console.log("fail--->wx.onBLECharacteristicValueChange :"+JSON.stringify(res)); } })

如果有多个特征值对象需要监听数据变化,则可以采取下列方式监听:

wx.onBLECharacteristicValueChange(function(res) { console.log(`characteristic ${res.characteristicId} has changed, now is ${res.value}`) console.log(ab2hex(res.value)) })



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3