收藏
回答

iOS蓝牙writeBLECharacteristicValue为啥10008 ?

代码片段不好使了,辛苦帮忙看看,特征的权限也都是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
  }
});
回答关注问题邀请回答
收藏
登录 后发表内容