步骤如下:
- 初始化蓝牙
- 扫描蓝牙设备
- 保存搜索到的设备到数据列表
- 选择蓝牙
- 获取蓝牙服务
- 获取蓝牙服务的特征值
- 通过特征值监听蓝牙消息
- 发送消息
初始化蓝牙 + 扫描蓝牙设备 + 保存搜索到的设备到数据列表
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
}