1、定义相关业务状态
蓝牙连接设备前,首先会想到一些各种的状态,比如等待连接、搜索设备中、已连接、连接失败等等一系列的状态监听,所以这里先定义好相关状态,以便业务逻辑判断。
export const BLUE_STATE = {
/**
* 蓝牙不可用
*/
UNAVAILABLE: {
label: '请检查手机蓝牙是否开启',
code: -1
},
/**
* 等待连接蓝牙
*/
READY: {
label: '等待连接蓝牙',
code: 10000
},
/**
* 等待连接蓝牙(重启蓝牙适配器)
*/
READYAGAIN: {
label: '等待连接蓝牙',
code: 10001
},
/**
* 正在搜索设备...
*/
SCANING: {
label: '正在搜索设备...',
code: 12000
},
/**
* 正在传输数据...
*/
TRANSMITDATA: {
label: '正在传输数据...',
code: 13000
},
/**
* 数据传输完成
*/
LOCKDATA: {
label: '数据已锁定',
code: 11000
},
/**
* 已连接蓝牙
*/
CONNECTSUCCESS: {
label: '已连接蓝牙',
code: 200
},
/**
* 写入特征已准备就绪
*/
WRITEREADY: {
label: '写入特征已准备就绪',
code: 201
},
/**
* 蓝牙连接已断开
*/
DISCONNECT: {
label: '蓝牙连接已断开',
code: 500
},
/**
* 连接失败, 请重试!
*/
CONNECTFAILED: {
label: '连接失败, 请重试!',
code: -2
},
/**
* 微信无位置权限
*/
NOLOCATIONPERMISSION: {
label: '您关闭了微信位置权限,请前往手机设置页打开权限后重试',
code: 10007
},
/**
* 当前系统版本过低,请升级后重试!
*/
VERSIONLOW: {
label: '当前系统版本过低,请升级后重试!',
code: 10009
},
/**
* 系统异常,请稍后重试!
*/
SYSTEMERROR: {
label: '系统异常,请稍后重试!',
code: 10008
}
}
2、封装蓝牙控制器监听函数
可自行拓展监听器
export const BleController = {
/**
* 蓝牙连接状态
*/
addConnectStateListen(callBack) {
this.public.bleConnectStateCallBack = callBack
},
/**
* 传输数据监听
*/
addTransferDataListen(callBack) {
this.public.bleProgressDataCallBack = callBack
},
/**
* 数据传输完成监听
*/
addLockDataListen(callBack) {
this.public.bleLockDataCallBack = callBack
},
/**
* 写入特征值状态
*/
addWriteStateListen(callBack) {
this.public.bleWriteStateCallBack = callBack
},
// 连接状态
connectStateListen(params) {
if (this.public.bleConnectStateCallBack) {
this.public.bleConnectStateCallBack(params)
}
},
// 数据传输中
transferDataListen(params) {
if (this.public.bleTransferDataCallBack) {
this.public.bleTransferDataCallBack(params)
}
},
// 测量完成
lockDataListen(params) {
if (this.public.bleLockDataCallBack) {
this.public.bleLockDataCallBack(params)
}
},
// 写入特征值状态
writeStateListen(params) {
if (this.public.bleWriteStateCallBack) {
this.public.bleWriteStateCallBack(params)
}
},
public: {
bleConnectStateCallBack: null,
bleTransferDataCallBack: null,
bleLockDataCallBack: null,
bleWriteStateCallBack: null,
}
}
3、封装蓝牙扫描&连接函数
整个流程比较长,具体API使用可查看uniapp官方文档
let bleControl = null
let bleConnectDeviceID = null
let currentDevice = {
}
let writeData = {
device: {
},
serviceID: '',
characteristicID: ''
}
export const Blue = {
/**
* 蓝牙连接状态:200-> 已连接;-1 ->未连接
*/
connectState: -1,
// 开始蓝牙设备扫描
start() {
bleControl = BleProtocol
this._lastLockData = ""
if(bleConnectDeviceID) {
// 设备已连接
this.connectState = 200
bleControl.connectStateListen(BLUE_STATE.CONNECTSUCCESS);
return
};
bleControl.connectStateListen(BLUE_STATE.READY)
// 打开蓝牙适配器
uni.openBluetoothAdapter({
success: (res) => {
this.startBluetoothDevicesDiscovery()
},
fail: (res) => {
console.error('打开蓝牙适配器失败:', res);
if (res.errCode === 10001) {
bleControl.connectStateListen(BLUE_STATE.UNAVAILABLE)
}
// Android 系统特有,系统版本低于 4.3 不支持 BLE
if(res.errCode === 10009) {
bleControl.connectStateListen(BLUE_STATE.VERSIONLOW)
}
if(res.errCode === 10008) {
bleControl.connectStateListen(BLUE_STATE.SYSTEMERROR)
}
},
complete: () => {
// 监听蓝牙适配器状态
uni.onBluetoothAdapterStateChange(res => {
console.log('蓝牙适配器状态:', res);
if (res.available) {
this._isDiscovering = res.discovering
bleControl.connectStateListen(BLUE_STATE.READYAGAIN)
this.startBluetoothDevicesDiscovery()
}else {
// 蓝牙模块未开启
bleControl.connectStateListen(BLUE_STATE.UNAVAILABLE)
}
})
}
})
},
// 关闭蓝牙连接,关闭状态监听,初始化状态
stop() {
if (bleConnectDeviceID) {
uni.closeBLEConnection({
deviceId: bleConnectDeviceID
})
}
writeData = {
}
bleConnectDeviceID = null
this.connectState = -1
this._isDiscovering = false
uni.closeBluetoothAdapter()
uni.offBluetoothAdapterStateChange()
uni.offBLEConnectionStateChange()
uni.stopBluetoothDevicesDiscovery()
},
// 停止蓝牙扫描
stopBluetoothDevicesDiscovery() {
uni.stopBluetoothDevicesDiscovery()
},
// 开始蓝牙扫描
startBluetoothDevicesDiscovery() {
if (this._isDiscovering) return
this._isDiscovering = true
uni.startBluetoothDevicesDiscovery({
allowDuplicatesKey: true,
success: (res) => {
bleControl.connectStateListen(BLUE_STATE.SCANING)
this.onBluetoothDeviceFound()
},
fail: (res) => {
console.log('位置失败--', res);
if(res.errCode === -1 && (res.errno === 1509008 || res.errno === 1509009)) {
this.stop()
bleControl.connectStateListen(BLUE_STATE.NOLOCATIONPERMISSION)
}
}
})
},
// 搜索附近设备
onBluetoothDeviceFound() {
uni.onBluetoothDeviceFound(res => {
res.devices.forEach(device => {
// device = {
// RSSI: -50,
// advertisData: ArrayBuffer(19),
// advertisServiceUUIDs: Array(2),
// connectable: true,
// deviceId: "EE59532DF324-4SFSD-34635D-BB893-76SGSDFV",
// localName: "shebeimingcheng",
// name: "shebeimingcheng",
// }
if (device.name !== 'shebeimingcheng') return
let abHex = this.ab2hex(device.advertisData)
let mac = this.ab2hex(device.advertisData.slice(2, 8), ':').toUpperCase()
device.macAddr = mac
// 根据自己的设备修改
if (abHex.length == 38) {
this.stopBluetoothDevicesDiscovery()
this.createBLEConnection(device)
}
})
})
},
// 创建蓝牙连接
createBLEConnection(device) {
if (bleConnectDeviceID == null) {
bleConnectDeviceID = device.deviceId
uni.createBLEConnection({
deviceId: device.deviceId,
success: res=> {
currentDevice = device
this.connectState = 200
// 蓝牙连接成功,上报设备信息
bleControl.connectStateListen({
...BLUE_STATE.CONNECTSUCCESS,
deviceInfo: {
...device}
})
this.getBLEDeviceServices(device)
this.onBLEConnectionStateChange()
},
fail: (err)=> {
bleControl.connectStateListen(BLUE_STATE.CONNECTFAILED)
},
})
}
},
// 监听连接状态
onBLEConnectionStateChange() {
uni.onBLEConnectionStateChange(res => {
console.log('蓝牙连接状态: ', res);
if (!res.connected) {
bleControl.connectStateListen(BLUE_STATE.DISCONNECT)
this.stop()
}
});
},
// 获取设备服务
getBLEDeviceServices(device) {
uni.getBLEDeviceServices({
deviceId: device.deviceId,
success: res=> {
for (let i = 0; i < res.services.length; i++) {
let uuid = res.services[i].uuid
if (uuid.indexOf("FFF0") == 0) {
this.getBLEDeviceCharacteristics(device, uuid)
}
}
},
})
},
// 获取设备特征值
getBLEDeviceCharacteristics(device, serviceID) {
uni.getBLEDeviceCharacteristics({
deviceId: device.deviceId,
serviceId: serviceID,
success: res=> {
for (let i = 0; i < res.characteristics.length; i++) {
let item = res.characteristics[i]
// 该特征值是否支持 write 操作
if (item.properties.write) {
if (item.uuid.indexOf("FFF1") == 0) {
writeData = {
device: device,
serviceID: serviceID,
characteristicID: item.uuid
}
bleControl.connectStateListen(BLUE_STATE.WRITEREADY);
}
}
// 该特征值是否支持 notify或indicate 操作
if (item.properties.notify || item.properties.indicate) {
if (item.uuid.indexOf("FFF4") == 0) {
this.notifyBLECharacteristicValueChange(device, serviceID, item.uuid);
}
}
}
}
})
},
// 监听特征值变化(设备数据变化)
notifyBLECharacteristicValueChange(device, serviceID, characteristicID) {
uni.notifyBLECharacteristicValueChange({
deviceId: device.deviceId,
serviceId: serviceID,
characteristicId: characteristicID,
state: true,
success: res=> {
this.onBLECharacteristicValueChange()
},
})
},
onBLECharacteristicValueChange() {
uni.onBLECharacteristicValueChange(res=> {
let value = this.ab2hex(res.value)
this.resolvingData(value)
})
},
// 发送指令给设备
sendOrder(byteArray) {
let checksum = 0x00
// byteArray = [FD, 03, 00, 01, 00]
// 计算异或和
for(let i = 0; i < byteArray.length - 1; i++) {
checksum ^= `0x${
byteArray[i]}`
}
this.deviceMode = mode
let sumStr = checksum.toString(16).toLocaleUpperCase()
let hex = byteArray.join('') + sumStr // FD03000100C4
let typedArray = new Uint8Array(hex.match(/[\da-f]{2}/gi).map(function(h) {
return parseInt(h, 16)
}))
let order = typedArray.buffer
if(!writeData.device.deviceId){
this.stop()
return
}
this.writeBLECharacteristicValue(order, writeData.device, writeData.serviceID, writeData.characteristicID)
},
// 写入特征值
writeBLECharacteristicValue(order, device, serviceID, characteristicID) {
uni.writeBLECharacteristicValue({
deviceId: device.deviceId,
serviceId: serviceID,
characteristicId: characteristicID,
value: order,
success: (res)=> {
console.log("特征值写入成功 --", res)
bleControl.writeStateListen({
code: res.errCode === 0 ? 200 : -1,
})
},
fail: (res)=> {
console.log("特征值写入失败 --", res)
bleControl.writeStateListen({
code: -1,
})
}
})
},
// ArrayBuffer转16进制字符串
ab2hex(buffer, split='') {
var hexArr = Array.prototype.map.call(new Uint8Array(buffer), function(bit) {
return ('00' + bit.toString(16)).slice(-2)
})
return hexArr.join(split)
},
// TODO 根据自己实际业务解析数据
resolvingData(res) {
if (this._lastLockData == res) return
this._lastLockData = res
const valArr = []
if (res.length >= 20) {
for (let i = 0, len = 10; i < len; i++) {
valArr[i] = res.substr(i * 2, 2)
}
// console.log(valArr);
}
},
}
4、业务组件使用蓝牙
Blue.start();
BleController.addConnectStateListen(state => {
console.log('蓝牙连接状态', state.code);
});
BleController.addTransferDataListen(info => {
console.log('数据传输中', info);
});
BleController.addWriteStateListen(res => {
console.log('特征值写入状态', res);
})
如果觉得有用随手点个赞吧,谢谢
关注我,不定时分享技术干货~