wx.onBLECharacteristicValueChange IOS能回调,安卓收不到
// index.js
Page({
data: {
CustomBar: getApp().globalData.CustomBar,
deviceList: [],
deviceId: null,
serviceId: null,
characteristicId: null,
characteristicId2: null,
deviceIndex: 0,
wifiName: null,
wifiPass: null,
isShow: false,
searchWifiShow: true,
wifiList: [],
isShowDialog: false,
isShowPassDialog: false,
wifiIndex:-1,
},
onLoad: function () {
},
onReady: function () {
},
onShow: function () {
wx.onGetWifiList((result) => {
console.log(result);
this.setData({
wifiList:result.wifiList
})
})
},
changeWifiName(e) {
var name = e.detail.value;
console.log("wifi-name > " + name);
this.setData({
wifiName: name
})
},
changeWifiPass(e) {
var pass = e.detail.value;
console.log("wifi-pass > " + pass);
this.setData({
wifiPass: pass
})
},
initBluetooth() {
let that = this;
this.clearData();
that.setData({
searchWifiShow:false
})
wx.showLoading({
title:'搜索中,请稍候...',
mask:true
});
wx.openBluetoothAdapter({
success: (res) => {
console.log('初始化蓝牙模块成功:', JSON.stringify(res));
this.findBluetoothList();
},
fail: (err) => {
console.log('初始化蓝牙模块失败:', JSON.stringify(err));
wx.hideLoading();
wx.showModal({
title: '提示',
content: '蓝牙未开启!请前往系统设置打开蓝牙~',
showCancel: false, // 是否显示取消按钮
confirmText: '我知道了', // 确认按钮的文本
confirmColor: '#3CC51F', // 确认按钮的文字颜色
success (res) {
if (res.confirm) {
console.log('用户点击确定')
that.setData({
searchWifiShow:true
})
}
}
})
}
});
},
findBluetoothList() {
let that = this;
wx.startBluetoothDevicesDiscovery({
allowDuplicatesKey: false,
success: (res) => {
console.log('开始扫描附近蓝牙设备:', JSON.stringify(res));
this.onBluetoothDeviceFound();
},
fail: (err) => {
that.setData({
searchWifiShow:true
})
wx.hideLoading();
console.log('扫描附近蓝牙设备失败:', JSON.stringify(err));
wx.showModal({
title: '提示',
content: '未搜索到相关配网设备~',
confirmText: '再试一次', // 确认按钮的文本
success (res) {
if (res.confirm) {
console.log('用户点击重试启动配网')
that.initBluetooth()
}
}
})
}
});
},
onBluetoothDeviceFound() {
let that = this;
wx.onBluetoothDeviceFound((res) => {
var newDevices = res.devices;
newDevices.isConn = false;
if (newDevices[0].name == "MX") {
console.log('找到蓝牙设备:', JSON.stringify(newDevices));
newDevices[0].shortId = newDevices[0].deviceId.split("-")[0]
var isAdd = false;
for (let j = 0; j < that.data.deviceList.length; j++) {
if (that.data.deviceList[j].deviceId == newDevices[0].deviceId) {
isAdd = true;
}
}
if(!isAdd){
this.setData({
deviceList: this.data.deviceList.concat(newDevices)
});
}
}
});
setTimeout(() => {
wx.hideLoading();
// 找到要搜索的设备后,及时停止扫描
wx.stopBluetoothDevicesDiscovery();
if(this.data.deviceList.length == 0){
that.setData({
searchWifiShow:true
})
wx.showModal({
title: '提示',
content: '未搜索到相关配网设备~',
confirmText: '再试一次', // 确认按钮的文本
success (res) {
if (res.confirm) {
console.log('用户点击重试启动配网')
that.initBluetooth()
}
}
})
}else{
that.setData({
searchWifiShow:false
})
}
}, 5000);
},
connBluetooth(e) {
let that = this;
// 当前已连接设备,再点击列表item连接时,断开当前连接的并清除信息
if (that.data.deviceId != null && that.data.serviceId != null) {
wx.closeBLEConnection({
deviceId: that.data.deviceId,
})
that.setData({
deviceList: that.data.deviceList,
deviceId: null,
serviceId: null,
characteristicId: null,
characteristicId2: null,
});
}
var name = e.currentTarget.dataset.name;
var deviceId = e.currentTarget.dataset.deviceId;
var index = e.currentTarget.dataset.index;
that.data.deviceIndex = index;
var isConn = that.data.deviceList[index].isConn;
if (isConn) {
wx.closeBLEConnection({
deviceId: deviceId,
success: () => {
that.data.deviceList[index].isConn = false;
that.setData({
deviceList: that.data.deviceList
})
wx.showToast({
title: name + '已断开',
icon: 'none'
})
}
})
} else {
wx.createBLEConnection({
deviceId, // 搜索到设备的 deviceId
success: () => {
// 连接成功,获取服务
that.data.deviceList[index].isConn = true;
that.setData({
deviceList: that.data.deviceList
})
wx.showToast({
title: name + '已连接',
icon: 'none'
})
wx.startWifi({
success(res){
wx.getWifiList({
success(e){
that.showModal()
}
})
}
})
wx.getBLEDeviceServices({
deviceId, // 搜索到设备的 deviceId
success: (res) => {
if (res.errCode == 0) {
wx.showToast({
title: res.errMsg,
icon: 'none'
})
console.log(deviceId + " > " + res.errMsg);
}
for (let i = 0; i < res.services.length; i++) {
console.log(JSON.stringify(res.services[i]));
if (res.services[i].isPrimary) {
var serviceId = res.services[i].uuid;
if (serviceId.startsWith('00000922')) {
wx.showToast({
title: '0922已找到',
icon: 'none'
})
this.writeAndRead(deviceId, serviceId);
}
}
}
},
fail: (err) => {
console.log(JSON.stringify(err));
}
})
}
})
}
},
writeAndRead(deviceId, serviceId) {
let that = this;
wx.getBLEDeviceCharacteristics({
deviceId, // 搜索到设备的 deviceId
serviceId, // 上一步中找到的某个服务
success: (res) => {
for (let i = 0; i < res.characteristics.length; i++) {
let item = res.characteristics[i]
console.log('特征值 >>> ' + JSON.stringify(item));
if (item.properties.write) { // 该特征值可写
that.setData({
deviceId: deviceId,
serviceId: serviceId,
characteristicId: item.uuid
})
}
if (item.properties.read) { // 该特征值可读
}
if (item.properties.notify || item.properties.indicate) {
that.setData({
characteristicId2: item.uuid
})
}
}
}
})
},
hexStringToArrayBuffer(hexString) {
const len = hexString.length / 2;
const buffer = new ArrayBuffer(len);
const dataView = new DataView(buffer);
for (let i = 0; i < len; i++) {
dataView.setUint8(i, parseInt(hexString.substr(i * 2, 2), 16));
}
return buffer;
},
// 发送数据函数
sendData() {
let that = this;
var mtu = 20;
wx.getBLEMTU({
deviceId: that.data.deviceId,
writeType: 'write',
success (res) {
console.log('getBLEMTU >>>');
console.log(res)
mtu = res.mtu;
console.log('getBLEMTU <<<');
}
})
console.log('获取到的mtu >>> '+mtu);
wx.setBLEMTU({
deviceId: that.data.deviceId,
mtu,
success(res){
console.log('setBLEMTU S>>>');
console.log(res);
console.log('setBLEMTU S>>>');
},
fail(err){
console.log('setBLEMTU F>>>');
console.log(res);
console.log('setBLEMTU F>>>');
}
})
if (that.data.wifiName == null || that.data.wifiPass == null) {
wx.showToast({
title: '请填写wifi信息~',
icon: 'none'
});
return;
}
that.hideModalPass()
that.hideModal()
var dataObj = {
ssid: that.data.wifiName,
password: that.data.wifiPass
}
var tranObj = {
type: 'apinfo',
data: dataObj
}
setTimeout(() => {
console.log('等3s再执行');
console.log("配网明文 > " + JSON.stringify(tranObj));
var jsonString = JSON.stringify(tranObj).replace(/:/g, ': ');
jsonString = jsonString.replace(/…/g, '...');
console.log("配网明文TRAN > " + jsonString);
var cmdHex = this.stringToHex(jsonString);
console.log("配网HEX > " + cmdHex);
const hexData = cmdHex;
console.log(JSON.stringify(that.data));
let buffer = this.hexStringToArrayBuffer(hexData);
const packages = this.splitDataIntoPackages(buffer,mtu-1);
const hexArray = this.traverseArrayBufferWithUint8Array(buffer);
console.log(hexArray.join(' '));
this.sendPackages(that.data.deviceId, that.data.serviceId, that.data.characteristicId, packages, () => {
console.log("end >>>>>");
console.log('2次确认 >>> ' + JSON.stringify(that.data));
// 延时设置通知
setTimeout(() => {
wx.readBLECharacteristicValue({
deviceId: that.data.deviceId,
serviceId: that.data.serviceId,
characteristicId: that.data.characteristicId2,
success: (res) => {
console.log('读取设备信息成功 >>> ' + JSON.stringify(res));
}
})
wx.notifyBLECharacteristicValueChange({
deviceId: that.data.deviceId,
serviceId: that.data.serviceId,
characteristicId: that.data.characteristicId2,
state: true,
type: 'notification',
success: (res) => {
console.log('监听已开启~');
wx.showToast({
title: '监听已开启~',
icon: 'none'
});
wx.showLoading({
title:'配网进行中,请耐心等待设备回执~(超过2分钟,请尝试重新配网)',
mask:true
})
wx.onBLECharacteristicValueChange((result) => {
var receiveText = that.buf2string(result.value);
console.log('监听到的数据回执1 >>> ' + receiveText);
// 两个输出结果是一样的,转换过程都一样,这里都打印,用一个就行
var content = that.receiveData(result.value);
console.log('监听到的数据回执2 >>> ' + content);
wx.hideLoading();
if (receiveText.indexOf('wifi_reply') !== -1) {
if (receiveText.indexOf('connected') !== -1) {
wx.showModal({
title: '提示',
content: '配网连接成功 > connected',
showCancel: false,
confirmText: '我知道了',
success (res) {
if (res.confirm) {
console.log('用户点击确定')
that.setData({
searchWifiShow:true
})
}
}
})
} else if (receiveText.indexOf('not') !== -1) {
wx.showModal({
title: '提示',
content: '未找到该WIFI > ap not found',
showCancel: false,
confirmText: '我知道了',
success (res) {
if (res.confirm) {
console.log('用户点击确定')
that.setData({
searchWifiShow:true
})
}
}
})
} else if (receiveText.indexOf('low') !== -1) {
wx.showModal({
title: '提示',
content: 'RSSI信号过低 > rssi too low',
showCancel: false,
confirmText: '我知道了',
success (res) {
if (res.confirm) {
console.log('用户点击确定')
that.setData({
searchWifiShow:true
})
}
}
})
} else if (receiveText.indexOf('fail') !== -1) {
wx.showToast({
title: '配网连接失败 > fail connected',
icon: 'none'
});
wx.showModal({
title: '提示',
content: '配网连接失败 > fail connected',
showCancel: false,
confirmText: '我知道了',
success (res) {
if (res.confirm) {
console.log('用户点击确定')
that.setData({
searchWifiShow:true
})
}
}
})
}
that.data.deviceList[that.data.deviceIndex].isConn = false;
that.setData({
deviceList: that.data.deviceList
})
}
});
},
fail: (err) => {
console.error('设置通知失败 >>>', err);
}
});
}, 200); // 设置 1 秒延时
});
},3000)
},
// 分包数据并添加前缀
splitDataIntoPackages(buffer,mtu) {
console.log('mtu size >>> '+ mtu);
const chunkSize = mtu; // 每包 20 字节,包括 1 字节前缀,实际数据 19 字节
const uint8Array = new Uint8Array(buffer);
const packages = [];
const totalLength = uint8Array.length;
for (let offset = 0; offset < totalLength; offset += chunkSize) {
let end = Math.min(offset + chunkSize, totalLength);
let chunk = uint8Array.slice(offset, end);
// 创建一个新的 Uint8Array 包含前缀和数据
const packageBuffer = new Uint8Array(chunk.length + 1);
// 添加前缀
if (offset === 0) {
packageBuffer[0] = 0x01; // 首包前缀
} else if (end === totalLength) {
packageBuffer[0] = 0x11; // 尾包前缀
} else {
packageBuffer[0] = 0x10; // 中间包前缀
}
// 将数据写入包中
packageBuffer.set(chunk, 1);
packages.push(packageBuffer.buffer);
}
return packages;
},
// 发送数据包
sendPackages(deviceId, serviceId, characteristicId, packages, callback) {
let that = this;
let index = 0;
function sendNextPackage() {
if (index < packages.length) {
const currentPackage = new Uint8Array(packages[index]);
const hexString = that.uint8ArrayToHexString(currentPackage);
console.log(`发送数据包 HEX >>> 包序号: ${index} 数据: ${hexString}`);
wx.writeBLECharacteristicValue({
deviceId: deviceId,
serviceId: serviceId,
characteristicId: characteristicId,
value: packages[index],
success: (res) => {
console.log(`发送数据包成功 >>> 包序号: ${index}`, JSON.stringify(res));
index++;
sendNextPackage(); // 发送下一个包
},
fail: (err) => {
console.error(`发送数据包失败 >>> 包序号: ${index}`, err);
}
});
} else {
console.log('所有数据包发送完成');
if (callback) callback();
}
}
sendNextPackage();
},
clearData() {
let that = this;
wx.closeBLEConnection({
deviceId: that.data.deviceId,
})
wx.closeBluetoothAdapter({})
that.setData({
deviceList: [],
deviceId: null,
serviceId: null,
characteristicId: null,
characteristicId2: null,
});
},
traverseArrayBufferWithUint8Array(buffer) {
const uint8Array = new Uint8Array(buffer);
const length = uint8Array.length;
const hexArray = [];
for (let i = 0; i < length; i++) {
// 获取每个字节并转换为 HEX 格式
const byte = uint8Array[i];
const hex = byte.toString(16).padStart(2, '0').toUpperCase();
hexArray.push(hex);
}
return hexArray;
},
// 将 Uint8Array 转换为 HEX 字符串
uint8ArrayToHexString(uint8Array) {
return Array.from(uint8Array).map(byte => byte.toString(16).padStart(2, '0').toUpperCase()).join(' ');
},
/* 转换成需要的格式 */
buf2string(buffer) {
var arr = Array.prototype.map.call(new Uint8Array(buffer), x => x)
return arr.map((char, i) => {
return String.fromCharCode(char);
}).join('');
},
receiveData(buf) {
return this.hexCharCodeToStr(this.ab2hex(buf))
},
/* 转成二进制 */
ab2hex(buffer) {
var hexArr = Array.prototype.map.call(
new Uint8Array(buffer), function (bit) {
return ('00' + bit.toString(16)).slice(-2)
}
)
return hexArr.join('')
},
/* 转成可展会的文字 */
hexCharCodeToStr(hexCharCodeStr) {
var trimedStr = hexCharCodeStr.trim();
var rawStr = trimedStr.substr(0, 2).toLowerCase() === '0x' ? trimedStr.substr(2) : trimedStr;
var len = rawStr.length;
var curCharCode;
var resultStr = [];
for (var i = 0; i < len; i = i + 2) {
curCharCode = parseInt(rawStr.substr(i, 2), 16);
resultStr.push(String.fromCharCode(curCharCode));
}
return resultStr.join('');
},
stringToHex(str) {
let hex = '';
for (let i = 0; i < str.length; i++) {
hex += str.charCodeAt(i).toString(16);
}
return hex;
},
showModal() {
let that = this;
that.setData({
isShowDialog: true,
})
},
hideModal() {
let that = this;
that.setData({
isShowDialog: false
})
},showModalPass() {
let that = this;
that.setData({
isShowPassDialog: true,
})
},
hideModalPass() {
let that = this;
that.setData({
isShowPassDialog: false
})
},connWifi(e){
let that = this;
var index = e.currentTarget.dataset.index;
var SSID = e.currentTarget.dataset.ssid;
that.setData({
wifiIndex:index,
wifiName:SSID
})
wx.showModal({
title: '提示',
content: '要连接此【'+SSID+'】网络配网吗?',
showCancel: true, // 是否显示取消按钮
confirmText: '是的', // 确认按钮的文本
confirmColor: '#3CC51F', // 确认按钮的文字颜色
cancelText: '取消',
success (res) {
if (res.confirm) {
console.log('用户点击确定')
that.showModalPass()
}else if (res.cancel) {
console.log('用户点击取消')
}
}
})
}
})
蓝牙连接,特征值等都正常,数据也可以正常发送设备,设备也回执了配网成功,ios可以正常收到设备给的回执,安卓始终收不到,获取和设置mtu 增加延迟 ,设置wx.notifyBLECharacteristicValueChange的type为‘notification’ 都尝试过了,只有ios正常,安卓就是不行啊