您的位置:首页 > 移动开发 > 微信开发

微信小程序蓝牙开发

2017-09-01 17:37 501 查看

微信小程序蓝牙开发

1、蓝牙模块(小程序蓝牙模块每一个操作都是通过封装好的API函数来 调用该功能,从成功回调函数里面得到需要的数据)

蓝牙连接过程:

1)初始化蓝牙适配器,执行初始化操作

// 打开蓝牙
openBluetooth:function () {
var that = this;
// 初始化蓝牙适配器
wx.openBluetoothAdapter({
success:function (res) {
console.log(res.errMsg);
wx.showToast({
title:"初始化成功",
duration:1000
});
},
fail:function (res) {
wx.showToast({
title:"请打开手机蓝牙",
duration:2000
});
}
})
// 获取本机蓝牙适配器状态
wx.getBluetoothAdapterState({
success:function(res) {
console.log("适配器状态:",res.errMsg)
}
})
wx.onBluetoothAdapterStateChange(function(res) {
console.log(`adapterState changed, now is`, res)
})
},


同时,调用wx.getBluetoothAdapterState(OBJECT),获取本机蓝牙适配器状态;调用wx.onBluetoothAdapterStateChange(CALLBACK)监听蓝牙适配器状态变化事件。

2)开始搜索设备

wx.onBluetoothAdapterStateChange(CALLBACK)

开始搜寻附近的蓝牙外围设备。注意,该操作比较耗费系统资源,请在搜索并连接到设备后调用 stop 方法停止搜索。

// 以我自己蓝牙设备为例,主服务的 UUID 是 FEE9。传入这个参数,只搜索主服务 UUID 为 FEE9 的设备,该参数也可以不设置

wx.getBluetoothDevices(OBJECT)获取所有已发现的蓝牙设备,包括已经和本机 处于连接状态的设备

已发现的设备在回调函数中,res.devices数组中。然后将数组保存在data中,通过渲染数据将发现的设备显示在页面上。

wx.startBluetoothDevicesDiscovery({
services: ['FEE9'],
success: function (res) {
console.log(res)
setTimeout(function () {
wx.getBluetoothDevices({
success: func
4000
tion (res) {
console.log(res.devices)
}
})
},3000)
}
})


3)连接设备

wx.createBLEConnection(OBJECT) 根据deviceID连接低功耗蓝牙设备

e为当前元素(需要连接的设备)属性,通过其携带的deviceId参数执行连接

connectTo: function (e) {
var that = this;
// console.log(e);
wx.createBLEConnection({
deviceId: e.currentTarget.id,
success: function (res) {
console.log("连接成功");
//将连接的deviceID暴露出来,以供后面使用
that.setData({
connectedDeviceId: e.currentTarget.id,
})
//将已连接设备的deviceID作为携带参数,进入test页面
wx.navigateTo({
Url: ‘../test?deviceId=’+that.data.connectedDeviceId,
Complete:function (rew){
Console.log(res)
}
})
//连接成功后执行停止搜索方法(性能优化)
wx.stopBluetoothDevicesDiscovery({
sucess:function (res) {
Console.log(res)
}
})
}
})
}


//连接成功后同时写一个监听函数

监听低功耗蓝牙连接的错误事件,包括设备丢失,连接异常断开等等。

wx.onBLEConnectionStateChange(function(res) {
// 该方法回调中可以用于处理连接意外断开等异常情况
console.log(`device ${res.deviceId} state has changed, connected:    ${res.connected}`)
})


4)页面间数据传递

页面间传递数据的坑:

我这里蓝牙数据量非常大并且需要实时传递。

开始是在蓝牙设备配对页面完成所有蓝牙操作,在该页面接收数据。问题出现在,蓝牙设备配对页面中接收到的数据无法实时传递到第二页面。

小程序中每个页面下都是独立的js文件,不互通,可以通过定义全局变量接收参数并传递。但是由于蓝牙设备 数据传输量巨大,并且需要达到实时传递的效果,通过定义全局变量方法,无法实现实时实时传递目的。

解决方案:设备连接上后,将deviceID作为携带参数,直接跳转到第二页面,在第二页面上完成后续的获取serviceID和特征值,完成蓝牙后续左右操作。

通过wx.navigateTo()方法携带的参数只能在onLoad函数中获取;

wx.getBLEDeviceServices(OBJECT)获取蓝牙设备所有service(服务)

wx.getBLEDeviceCharacteristics(OBJECT)获取蓝牙设备所有 characteristic(特征值)

通过deviceID获得serviceID。(安卓和iOS不同,安卓为小写。后续API更新将统一为大写),下一步,通过一个延迟函数,等获取serviceID后再获取Characteristics(特征值),根据需求分别获取读取通道和写入通道特征值,将以上获取的值赋值给data中的变量。

注意:serviceId和特征值uuid 都是事先知道的,然后在获取的值中匹配。很多小伙伴都在这里遇到问题,如果你不知道serviceID 和 uuid的话,我只能说你去找硬件要了。。。

getBLEDeviceServices:function () {
var that = this;
// 获取蓝牙设备所有service(服务)
wx.getBLEDeviceServices({
deviceId:that.data.connectedDeviceId,
success:function (res) {
for (var i = 0; i < res.services.length; i++) {
// 安卓和iOS不同,安卓为小写。后续API更新将统一为大写
//判断是否为需要的UUID
if (res.services[i].uuid.indexOf("fee9") > 0 || res.services[i].uuid.indexOf("FEE9") > 0) {
that.setData({
serviceId : res.services[i].uuid
})
}
}
}
})
// 获取蓝牙设备所有characteristic(特征值)
setTimeout(function (){
wx.getBLEDeviceCharacteristics({
deviceId:that.data.connectedDeviceId,
serviceId: that.data.serviceId,
success:function (res) {
for (var i = 0; i < res.characteristics.length; i++) {
if(res.characteristics[i].uuid.indexOf('129601') > 0 ) {
that.setData({
readCharacteristic:res.characteristics[i].uuid
})
}
if (res.characteristics[i].uuid.indexOf('129600') > 0) {
that.setData({
writeCharacteristic : res.characteristics[i].uuid
})
}
}
}
})
},500)
}


到此,蓝牙设备连接完毕。下面进行读写命令操作

5)读写监听数据

首先,wx.notifyBLECharacteristicValueChange(OBJECT)启用低功耗蓝牙设备特征值变化时的 notify 功能。注意:必须设备的特征值支持notify才可以成功调用,具体参照 characteristic 的 properties 属性

另外,必须先启用notify才能监听到设备 characteristicValueChange 事件。characteristieValueChange事件只调用一次即可,切忌像小程序API中每个写入函数都调用characteristieValueChange事件(此处为坑)

蓝牙API中提供了wx.readBLECharacteristicValue(OBJECT)方法和wx.writeBLEChatracteristicValue(OBJECT)方法。但是,经过讨论和实践,read方法没有作用,读取到的数据都在characteristieValueChange函数中获取。

// 开启notify通道
notifyBLECharacteristicValueChange:function () {
var that = this;
wx.notifyBLECharacteristicValueChange({
state: true, // 启用 notify 功能
// 这里的 deviceId 需要在上面的 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
deviceId: that.data.connectedDeviceId,
// 这里的 serviceId 需要在上面的 getBLEDeviceServices 接口中获取
serviceId: that.data.serviceId,
// 这里的 characteristicId 需要在上面的 getBLEDeviceCharacteristics 接口中获取
characteristicId: that.data.readCharacteristic,
success: function (res) {
// 安卓bug,加个延迟
setTimeout(function () {
that.onWrite();
},500);
// IOS
// that.onWrite();
}
})
wx.onBLECharacteristicValueChange(function(res) {
//此处为坑,vConsole 无法打印出 ArrayBuffer 类型数据。需要将监听到的数据转换成字符串,才能被后面使用。
let hex = Array.prototype.map.call(new Uint8Array(res.value), x => ('00' + x.toString(16)).slice(-2)).join('');
that.setData({
returnValue:hex
})
})
}


写入方法:

onWrite:function () {
var that = this;
// wirte里面不要写监听函数
// 向蓝牙设备发送一个0x00的16进制数据
let buffer = new ArrayBuffer(5);
let dataView = new DataView(buffer);
dataView.setUint8(0,0x0f)
dataView.setUint8(1,0x0f)
dataView.setUint8(2,0x57)
dataView.setUint8(3,0x46)
dataView.setUint8(4,0x78)
//可以通过getUint8(0)的方法取到setUint8()的值
// console.log(dataView.getUint8(0))
wx.writeBLECharacteristicValue({
// 这里的 deviceId 需要在上面的 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
deviceId: that.data.connectedDeviceId,
// 这里的 serviceId 需要在上面的 getBLEDeviceServices 接口中获取
serviceId: that.data.serviceId,
// 这里的 characteristicId 需要在上面的 getBLEDeviceCharacteristics 接口中获取
characteristicId: that.data.writeCharacteristic,
// 这里的value是ArrayBuffer类型
value: buffer,
success: function (res) {
console.log(res);
},
fail: function (res) {
console.log(res);
}
})
}


写入方法的坑:

// 向蓝牙设备发送一个0x00的16进制数据

let buffer = new ArrayBuffer(1)

let dataView = new DataView(buffer)

dataView.setUint8(0, 0)

此处用到的是JavaScript中ArratBuffer类型化数组 数据类型。

首先将写入命令转换成0x00类型的16进制数据;

Buffer = new ArrayBuffer(1)中,1为开辟的内存空间的数量,根据命令的个数填入所需要的内存空间。

dataView.setUint8(0,0);第一个参数为下标从0开始,第二个参数为命令。循环命令的长度,将所有命令setUint8写入。可以通过dataView.getUint8()

下图为其中一条创建新key命令,如果将命令赋值给变量的时候,此时数据类型就会改变,因此只能对每个写入命令单独写一个函数调用write方法。

安卓手机连接蓝牙的坑:

安卓手机在连接上,notify函数中会报一个10008(其余所有系统上报的异常)的错误码,此处可以理解为小程序蓝牙自身的bug。

解决方法:在notify的成功回调函数里面调用写入方法的时候,给写入方法加一个延迟函数,调用,就正常了。

还有一种情况,可以在notify的失败回调函数里继续执行下一步操作,也可能会正常操作。

该问题有可能在后续API更新后得以解决。

欢迎大家指导,交流!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: