用 UniApp 开发微信小程序蓝牙通信功能

步骤如下:

  1. 初始化蓝牙
  2. 扫描蓝牙设备
  3. 保存搜索到的设备到数据列表
  4. 选择蓝牙
  5. 获取蓝牙服务
  6. 获取蓝牙服务的特征值
  7. 通过特征值监听蓝牙消息
  8. 发送消息

初始化蓝牙 + 扫描蓝牙设备 + 保存搜索到的设备到数据列表

js 复制代码
const data = []
uni.openBluetoothAdapter({
  success(res) {
    console.log('蓝牙初始化成功--openBluetoothAdapter', res)
    // 以微信硬件平台的蓝牙智能灯为例,主服务的 UUID 是 FEE7。传入这个参数,只搜索主服务 UUID 为 FEE7 的设备
    uni.startBluetoothDevicesDiscovery({
      services: ['硬件设备的uuid'],
      success(res) {},
    })
    uni.onBluetoothDeviceFound(res => {
      console.log('搜索到新设备', res)
      data.push(...res)
    })
  },
  fail(e) {
    switch (e.errCode) {
      case 10001:
        console.log('当前蓝牙适配器不可用')
        break
      default:
        console.log('蓝牙打开失败', e)
        break
    }
  },
})

选择蓝牙

js 复制代码
const connectDevice = item => {
  uni.showLoading({
    title: '连接中...',
  })
  uni.createBLEConnection({
    deviceId: item.deviceId,
    success: res => {
      console.log('蓝牙连接成功', res)
      getServices(item.deviceId)
    },
    fail: err => {
      console.log('蓝牙连接失败', err)
      uni.hideLoading()
      uni.showToast({
        title: '蓝牙连接失败,请重试',
        icon: 'none',
      })
    },
  })
}

获取蓝牙服务

js 复制代码
const getServices = deviceId => {
  uni.getBLEDeviceServices({
    deviceId: deviceId,
    success: res => {
      console.log('获取服务成功', res.services)
      if (res.services.length > 0) {
        // 通常使用第一个服务
        const serviceId = res.services[0].uuid
        getCharacteristics(deviceId, serviceId)
      }
    },
    fail: err => {
      console.error('获取服务失败', err)
    },
  })
}

获取蓝牙服务的特征值

js 复制代码
// 获取特征值
const getCharacteristics = (deviceId, serviceId) => {
  uni.getBLEDeviceCharacteristics({
    deviceId: deviceId,
    serviceId: serviceId,
    success: res => {
      console.log('获取特征值成功', res.characteristics)
      // 寻找可读写的特征值(具体需要与开发安卓应用的同事沟通,也有可能读写用的不是同一个特征值)
      const characteristic = res.characteristics.find(char => {
        return char.properties.read && char.properties.write && char.properties.notify
      })

      if (characteristic) {
        enableNotify(deviceId, serviceId, characteristic.uuid)
      } else {
        console.log('没有找到可读写的特征值')
      }
    },
    fail: err => {
      console.error('获取特征值失败', err)
    },
  })
}

通过特征值监听蓝牙消息

js 复制代码
// 启用通知
const enableNotify = () => {
  // connectedDevice是用来存储 设备id,服务id,特征值id的对象,根据自己项目的实现写
  const { deviceId, serviceId, characteristicIdNotify } = connectedDevice.value
  uni.notifyBLECharacteristicValueChange({
    deviceId,
    serviceId,
    characteristicId: characteristicIdNotify,
    state: true,
    success: res => {
      console.log('启用通知成功')
      listenData()
      // 监听信息时不要直接发送消息,容易报错 10008
      setTimeout(() => {
        sendData(`e0`, false)
      }, 2000)
    },
    fail: err => {
      console.error('启用通知失败', err)
    },
  })
}

// 监听数据接收
const listenData = () => {
  uni.onBLECharacteristicValueChange(res => {
    console.log('接收到数据', res)
    /** 先将接收到的字节数组转换为16进制字符串,再转换为字符串 */
    const hexValue = ab2hex(res.value)
    const strValue = hex2str(hexValue)
    console.log('数据内容:', strValue)
  })
}

发送消息

js 复制代码
// 发送数据到设备
const sendData = (data, isString = true) => {
  if (!connectedDevice.value) {
    uni.showToast({
      title: '未连接设备',
      icon: 'none',
    })
    return
  }

  const { deviceId, serviceId, characteristicIdWrite } = connectedDevice.value
  // 判断发送的数据是字符串还是16进制字符串,如果是普通字符串需要先转换为16进制字符串
  const hexString = isString ? str2hex(data) : data
  // 发送蓝牙信息时需要转换为字节数组进行传输
  const buffer = hex2ab(hexString)

  uni.writeBLECharacteristicValue({
    deviceId: deviceId,
    serviceId: serviceId,
    characteristicId: characteristicIdWrite,
    value: buffer,
    success: res => {
      uni.hideLoading()
      uni.showToast({
        title: '发送数据成功',
        icon: 'success',
      })
      console.log('发送数据成功')
    },
    fail: err => {
      uni.hideLoading()
      uni.showToast({
        title: '发送数据失败,请重试',
        icon: 'none',
      })
      console.error('发送数据失败', err)
    },
  })
}

字符、十六进制字符、arrayBuffer 之间的转换方法

js 复制代码
/** 字符串转16进制 */
export const str2hex = str => {
  let hex = ''
  for (let i = 0; i < str.length; i++) {
    let charCode = str.charCodeAt(i)
    let hexCode = charCode.toString(16)
    hex += hexCode.padStart(2, '0')
  }
  return hex
}

// ArrayBuffer转16进制字符串
export const ab2hex = buffer => {
  const hexArr = Array.prototype.map.call(new Uint8Array(buffer), bit =>
    ('00' + bit.toString(16)).slice(-2),
  )
  return hexArr.join('')
}

// 16进制字符串转字节数组
export const hex2ab = hexString => {
  hexString = hexString.replace(/\s/g, '').replace(/^0x/, '')

  if (hexString.length % 2 !== 0) {
    hexString = '0' + hexString
  }

  const byteLength = hexString.length / 2
  const bytes = new Uint8Array(byteLength)

  for (let i = 0; i < byteLength; i++) {
    bytes[i] = parseInt(hexString.substr(i * 2, 2), 16)
  }

  return bytes.buffer
}

// 16进制转字符串
export const hex2str = hex => {
  let str = ''
  for (let i = 0; i < hex.length; i += 2) {
    const hexValue = hex.substr(i, 2)
    const charCode = parseInt(hexValue, 16)
    str += String.fromCharCode(charCode)
  }
  return str
}
相关推荐
勤奋菲菲4 小时前
深入理解HTML文本标签:构建网页内容的基础
前端·html
昔人'4 小时前
html`<mark>`
前端·javascript·html
云中雾丽4 小时前
Flutter主流的本地存储方案
前端
ss2734 小时前
手写Spring第7弹:Spring IoC容器深度解析:XML配置的完整指南
java·前端·数据库
前端拿破轮5 小时前
从0到1搭一个monorepo项目(二)
前端·javascript·面试
止观止5 小时前
XSS 攻击详解:原理、类型与防范策略
前端·xss
用户47949283569155 小时前
用|运算符写管道?Symbol.toPrimitive让JavaScript提前用上|>语法
前端·javascript
知识分享小能手5 小时前
uni-app 入门学习教程,从入门到精通,uni-app 基础知识详解 (2)
前端·javascript·windows·学习·微信小程序·小程序·uni-app
文心快码BaiduComate5 小时前
限时集福!Comate挂件/皮肤上线,符(福)气掉落中~
前端·后端·程序员