代码片段不好使了,辛苦帮忙看看,特征的权限也都是true,但是写入时候提示不允许
Page({
data: {
// 蓝牙状态
bleStatus: '蓝牙未初始化',
isBleReady: false, // 蓝牙适配器是否就绪
isScanning: false, // 是否正在扫描
isConnected: false, // 是否已连接从机
// 设备与通信数据
deviceList: [], // 扫描到的设备列表
deviceId: '', // 已连接设备的deviceId
serviceId: '', // 目标服务UUID
characteristicId: '', // 目标特征值UUID
sendData: '', // 要发送给从机的内容
notifyData: [] // 从机推送的通知数据
},
// ************************ 核心配置:修改为你的从机UUID ************************
SERVICE_UUID: '0000FFF7-0000-1000-8000-00805F9B34FB', // 从机服务UUID
CHARACTERISTIC_UUID: 'CCE62C0F-1098-4CD0-ADFA-C8FC7EA2EE92', // 从机特征值UUID
SCAN_TIME: 5000, // 扫描时长(ms),默认5秒
// ********************************************************************************
onUnload() {
// 页面卸载,清理蓝牙资源
this.cleanupBleResources();
},
/**
* 1. 初始化蓝牙适配器(所有蓝牙操作的基础)
*/
openBleAdapter() {
wx.showLoading({ title: '初始化蓝牙...' });
// 先关闭旧适配器,避免资源占用
wx.closeBluetoothAdapter({ fail: () => {} });
// 初始化新适配器
wx.openBluetoothAdapter({
success: () => {
this.setData({
bleStatus: '蓝牙初始化成功,可开始扫描',
isBleReady: true
});
wx.hideLoading();
wx.showToast({ title: '蓝牙初始化成功', icon: 'success' });
},
fail: (err) => {
wx.hideLoading();
let msg = '蓝牙初始化失败,请先开启手机蓝牙';
if (err.errCode === 10001) msg = '手机蓝牙未开启,请手动开启';
this.setData({ bleStatus: msg });
wx.showToast({ title: msg, icon: 'none', duration: 3000 });
console.error('openBluetoothAdapter fail:', err);
}
});
},
/**
* 修复后:开始扫描BLE从机设备(核心修改设备过滤逻辑的 deviceList 访问方式)
*/
startScan() {
// 清空历史设备列表(正确写法:this.setData 修改 data 变量)
this.setData({
deviceList: [],
isScanning: true,
bleStatus: '正在扫描BLE设备...'
});
// 开始扫描(仅扫描低功耗BLE设备)
wx.startBluetoothDevicesDiscovery({
services: [this.SERVICE_UUID],
allowDuplicatesKey: false,
success: () => {
// 监听扫描到新设备的事件
wx.onBluetoothDeviceFound((res) => {
const devices = res.devices;
devices.forEach(device => {
// 🔴 核心修复:deviceList → this.data.deviceList
if (!device.deviceId || this.data.deviceList.some(item => item.deviceId === device.deviceId)) return;
console.log('发现设备', device);
// 🔴 注意:data 变量仅能通过 this.setData 修改,不可直接 this.data.deviceList.push
this.data.deviceList.push(device);
this.setData({ deviceList: this.data.deviceList });
});
});
// 定时停止扫描
setTimeout(() => {
if (this.data.isScanning) { // 🔴 顺带修复:isScanning → this.data.isScanning
this.stopScan();
this.setData({
bleStatus: `扫描结束,共发现${this.data.deviceList.length}台设备` // 🔴 deviceList → this.data.deviceList
});
}
}, this.SCAN_TIME);
},
fail: (err) => {
this.setData({ isScanning: false, bleStatus: '扫描失败' });
wx.showToast({ title: '扫描失败', icon: 'none' });
console.error('startBluetoothDevicesDiscovery fail:', err);
}
});
},
/**
* 停止扫描BLE设备
*/
stopScan() {
wx.stopBluetoothDevicesDiscovery({
success: () => {
this.setData({ isScanning: false });
// 移除扫描监听,避免内存泄漏
wx.offBluetoothDeviceFound();
},
fail: (err) => console.error('stopBluetoothDevicesDiscovery fail:', err)
});
},
/**
* 3. 连接选中的BLE从机设备
* @param {Object} e - 点击事件,携带deviceId
*/
connectDevice(e) {
const deviceId = e.currentTarget.dataset.deviceid;
if (!deviceId) return;
wx.showLoading({ title: '连接设备...' });
// 先停止扫描,再连接(避免扫描干扰连接)
this.stopScan();
this.setData({ deviceId, bleStatus: `正在连接设备[${deviceId}]...` });
// 建立BLE连接
wx.createBLEConnection({
deviceId,
success: () => {
this.setData({ isConnected: true, bleStatus: `设备连接成功[${deviceId}]` });
// 4. 连接成功后,发现从机的所有服务
this.discoverServices(deviceId);
},
fail: (err) => {
wx.hideLoading();
this.setData({ bleStatus: '设备连接失败' });
wx.showToast({ title: '连接失败', icon: 'none' });
console.error('createBLEConnection fail:', err);
}
});
// 监听设备断开连接的事件
wx.onBLEConnectionStateChange((res) => {
if (res.deviceId === deviceId && !res.connected) {
this.setData({
isConnected: false,
bleStatus: '设备已断开连接',
serviceId: '',
characteristicId: ''
});
wx.showToast({ title: '设备已断开', icon: 'none' });
// 移除相关监听
this.offBleListeners();
}
});
},
/**
* 4. 发现从机设备的所有服务
* @param {string} deviceId - 已连接设备的deviceId
*/
discoverServices(deviceId) {
wx.getBLEDeviceServices({
deviceId,
success: (res) => {
const services = res.services;
// 找到目标服务(与从机的SERVICE_UUID一致)
const targetService = services.find(service => service.uuid === this.SERVICE_UUID);
if (!targetService) {
wx.hideLoading();
this.setData({ bleStatus: '未找到目标服务,通信失败' });
wx.showToast({ title: '未找到目标服务', icon: 'none' });
return;
}
console.log("目标服务---", targetService);
this.setData({ serviceId: targetService.uuid });
// 5. 发现目标服务下的所有特征值
this.discoverCharacteristics(deviceId, targetService.uuid);
},
fail: (err) => {
wx.hideLoading();
this.setData({ bleStatus: '发现服务失败' });
console.error('getBLEDeviceServices fail:', err);
}
});
},
/**
* 5. 发现目标服务下的所有特征值
* @param {string} deviceId - 设备ID
* @param {string} serviceId - 目标服务ID
*/
discoverCharacteristics(deviceId, serviceId) {
wx.getBLEDeviceCharacteristics({
deviceId,
serviceId,
success: (res) => {
wx.hideLoading();
const characteristics = res.characteristics;
// 找到目标特征值(与从机的CHARACTERISTIC_UUID一致)
const targetChar = characteristics.find(char => char.uuid === this.CHARACTERISTIC_UUID);
if (!targetChar) {
this.setData({ bleStatus: '未找到目标特征值,通信失败' });
wx.showToast({ title: '未找到目标特征值', icon: 'none' });
return;
}
this.setData({
characteristicId: targetChar.uuid,
bleStatus: '设备通信就绪,可进行数据交互'
});
// 🔴 关键校验:特征值是否支持notify(从机必须开启notify属性,否则开启失败)
if (!targetChar.properties.notify) {
wx.showToast({ title: '特征值不支持通知(notify)', icon: 'none' });
console.error('从机特征值未开启notify属性,无法监听通知');
return;
}
console.log("目标特征---", targetChar);
wx.showToast({ title: '设备连接成功,通信就绪', icon: 'success' });
// 6. 开启特征值通知监听(关键:接收从机主动推送的notify数据)
this.openCharacteristicNotify(deviceId, serviceId, targetChar.uuid);
},
fail: (err) => {
wx.hideLoading();
this.setData({ bleStatus: '发现特征值失败' });
console.error('getBLEDeviceCharacteristics fail:', err);
}
});
},
/**
* 6. 开启特征值通知监听(接收从机notify数据的前提,BLE协议强制要求)
* @param {string} deviceId - 设备ID
* @param {string} serviceId - 服务ID
* @param {string} charId - 特征值ID
*/
openCharacteristicNotify(deviceId, serviceId, charId) {
wx.notifyBLECharacteristicValueChange({
deviceId,
serviceId,
characteristicId: charId,
state: true, // 开启通知
success: () => {
// 监听特征值变化(接收从机推送的通知数据)
wx.onBLECharacteristicValueChange((res) => {
// 转换从机的ArrayBuffer数据为字符串
// const data = this.arrayBufferToString(res.value);
// this.data.notifyData.unshift(`[${new Date().toLocaleTimeString()}] ${data}`);
// this.setData({ notifyData });
console.log('接收到从机通知数据:', res);
});
},
fail: (err) => {
this.setData({ bleStatus: '开启通知监听失败,无法接收从机数据' });
console.error('notifyBLECharacteristicValueChange fail:', err);
}
});
},
/**
* 7. 读取从机特征值的当前数据
*/
readDataFromPeripheral() {
const { deviceId, serviceId, characteristicId } = this.data;
if (!this.checkConnectStatus()) return;
wx.showLoading({ title: '读取数据...' });
wx.readBLECharacteristicValue({
deviceId,
serviceId,
characteristicId,
success: () => {
// 读取的结果会在 onBLECharacteristicValueChange 中返回
wx.hideLoading();
wx.showToast({ title: '读取指令已发送', icon: 'success' });
},
fail: (err) => {
wx.hideLoading();
wx.showToast({ title: '读取失败', icon: 'none' });
console.error('readBLECharacteristicValue fail:', err);
}
});
},
/**
* 8. 写入数据到从机特征值(主机→从机发送数据)
*/
writeDataToPeripheral() {
const { deviceId, serviceId, characteristicId, sendData } = this.data;
if (!this.checkConnectStatus() || !sendData.trim()) {
wx.showToast({ title: '请输入要发送的内容', icon: 'none' });
return;
}
wx.showLoading({ title: '发送数据...' });
// 字符串转ArrayBuffer(BLE通信标准格式,兼容无TextEncoder环境)
const buffer = this.string2buffer(sendData.trim());
wx.getBLEDeviceServices({
deviceId: deviceId,
success(e) {
console.log("获取到的设备的services")
console.log(e.services);
const targetService = e.services.find(service => service.uuid === serviceId);
if(!targetService){
return;
}
var serviceID = targetService.uuid;
wx.getBLEDeviceCharacteristics({
deviceId: deviceId,
serviceId: serviceID,
success(e) {
const characteristics = e.characteristics;
// 找到目标特征值(与从机的CHARACTERISTIC_UUID一致)
const targetChar = characteristics.find(char => char.uuid === characteristicId);
if(!targetChar){
return;
}
var charId = targetChar.uuid;
console.log('获取到的设备特征值')
console.log(e.characteristics)
wx.onBLECharacteristicValueChange((result) => {
console.log(result)
console.log(that.buf2string(result.value))
})
wx.writeBLECharacteristicValue({
characteristicId: charId,
deviceId: deviceId,
serviceId: serviceID,
value: buffer,
success(e) {
console.log(e.errMsg)
wx.hideLoading({
success: (res) => {
wx.showToast({
title: '发送成功',
icon:'none'
})
},
})
},
fail(e) {
wx.hideLoading({
success: (res) => {
wx.showToast({
title: '写入错误,发送失败',
icon: 'none'
})
},
})
console.log(e.errMsg)
}
})
},
fail(e) {
console.log(e.errMsg)
}
})
},
fail(e) {
wx.hideLoading({
success: (res) => {
wx.showToast({
title: '发送失败,无法获取服务',
icon: 'none'
})
},
})
console.log(e.errMsg)
}
})
// const buffer = new ArrayBuffer(3);
// wx.writeBLECharacteristicValue({
// deviceId,
// serviceId,
// characteristicId,
// value: buffer, // 必须为ArrayBuffer格式
// success: () => {
// wx.hideLoading();
// wx.showToast({ title: '发送成功', icon: 'success' });
// // 清空输入框
// this.setData({ sendData: '' });
// console.log('主机发送数据:', sendData.trim());
// },
// fail: (err) => {
// wx.hideLoading();
// wx.showToast({ title: '发送失败', icon: 'none' });
// console.error('writeBLECharacteristicValue fail:', err);
// }
// });
},
/**
* 断开与从机的连接
*/
disconnect() {
if (!this.data.isConnected) return;
wx.showLoading({ title: '断开连接...' });
wx.closeBLEConnection({
deviceId: this.data.deviceId,
success: () => {
this.setData({
isConnected: false,
bleStatus: '设备已断开连接',
serviceId: '',
characteristicId: '',
notifyData: []
});
wx.hideLoading();
wx.showToast({ title: '已断开连接', icon: 'success' });
// 移除蓝牙监听
this.offBleListeners();
},
fail: (err) => {
wx.hideLoading();
wx.showToast({ title: '断开失败', icon: 'none' });
console.error('closeBLEConnection fail:', err);
}
});
},
/**
* 关闭蓝牙适配器
*/
closeBleAdapter() {
this.cleanupBleResources();
this.setData({
bleStatus: '蓝牙已关闭',
isBleReady: false,
isScanning: false,
isConnected: false,
deviceList: [],
notifyData: []
});
wx.showToast({ title: '蓝牙已关闭', icon: 'success' });
},
/**
* 清理蓝牙资源(移除监听+关闭适配器)
*/
cleanupBleResources() {
// 移除所有蓝牙监听事件
this.offBleListeners();
// 停止扫描+断开连接+关闭适配器
wx.stopBluetoothDevicesDiscovery({ fail: () => {} });
wx.closeBLEConnection({ deviceId: this.data.deviceId, fail: () => {} });
wx.closeBluetoothAdapter({ fail: () => {} });
},
/**
* 移除所有蓝牙监听事件,避免内存泄漏
*/
offBleListeners() {
wx.offBluetoothDeviceFound();
wx.offBLEConnectionStateChange();
wx.offBLECharacteristicValueChange();
},
/**
* 检查设备连接状态
* @returns {boolean} 已连接返回true,否则false
*/
checkConnectStatus() {
const { isConnected, deviceId, serviceId, characteristicId } = this.data;
if (!isConnected || !deviceId || !serviceId || !characteristicId) {
wx.showToast({ title: '设备未连接或通信未就绪', icon: 'none' });
return false;
}
return true;
},
/**
* 输入框内容变化监听
*/
onInputChange(e) {
this.setData({ sendData: e.detail.value });
},
buf2string: function (buffer) {
var arr = Array.prototype.map.call(new Uint8Array(buffer), x => x)
var str = ''
for (var i = 0; i < arr.length; i++) {
str += String.fromCharCode(arr[i])
}
return str
},
string2buffer: function (str) {
// 首先将字符串转为16进制
let val = ""
for (let i = 0; i < str.length; i++) {
if (val === '') {
val = str.charCodeAt(i).toString(16)
} else {
val += ',' + str.charCodeAt(i).toString(16)
}
}
// 将16进制转化为ArrayBuffer
return new Uint8Array(val.match(/[\da-f]{2}/gi).map(function (h) {
return parseInt(h, 16)
})).buffer
}
});
