uniAPP实现安卓iOS逃不过与硬件打交道的状况,本文记录一下uniAPP蓝牙衔接相关状况

1.初始化蓝牙设备 | | 提示用户翻开蓝牙设备

//设置运用变量
let discoveryStarted = false;
let deviceId = '';
let deviceName = '';
let characteristicId = ''; //uuid
let serviceId = '';
let rssiTimer = '';
let rssi = 3; //蓝牙信号强度 1级:近身大于-60,2级:近距离-70~-60, 三级:远距离低于-70
//翻开蓝牙适配器
function openBluetoothAdapter(callBack) {
	uni.openBluetoothAdapter({
		success: res => {
			console.log('翻开蓝牙适配器 success', res);
			startBluetoothDevicesDiscovery(callBack);
		},
		fail: res => {
			console.log('翻开蓝牙适配过错', res);
			if (res.code == 10001) {
				uni.showToast({
					title: '请先翻开手机蓝牙',
					icon: 'none'
				});
				uni.onBluetoothAdapterStateChange(res => {
					if (res.available){
                                        startBluetoothDevicesDiscovery(callBack);
					}
				});
			}
		}
	});
}

2.查找周边设备(此操作比较消耗系统资源,请在查找并衔接到设备后调用 uni.stopBluetoothDevicesDiscovery 办法中止查找。)

//敞开蓝牙查找
function startBluetoothDevicesDiscovery(callBack) {
	uni.startBluetoothDevicesDiscovery({
		allowDuplicatesKey: true,
		success: res => {
			console.log('敞开蓝牙查找 success', res);
			onBluetoothDeviceFound(callBack);
		},
		fail: res => {
			console.log('敞开蓝牙查找 err', res);
		}
	});
}

3.监听蓝牙设备列表

function onBluetoothDeviceFound(callBack) {
	uni.onBluetoothDeviceFound(res => {
		console.log('监听蓝牙设备列表',res.devices)
		res.devices.forEach(device => {
			if (device.name.indexOf(deviceName) == -1) {
				return;
			}
			createBLEConnection(device, callBack);
		});
	});
}

4.树立衔接并中止蓝牙查找

function createBLEConnection(device, callBack) {
	deviceId = device.deviceId;
	uni.createBLEConnection({
		deviceId,
		success: res => {
			console.log('树立衔接成功', res)
			//获取蓝牙设备服务
			getBLEDeviceServices(deviceId, callBack);
		}
	});
	stopBluetoothDevicesDiscovery();
}
//中止蓝牙查找
function stopBluetoothDevicesDiscovery() {
	uni.stopBluetoothDevicesDiscovery();
	discoveryStarted = false;
}

5.获取蓝牙设备服务

function getBLEDeviceServices(deviceId, callBack) {
    //重复获取,知道获取到停止
    let timer = setInterval(() => {
	uni.getBLEDeviceServices({
            deviceId,
            success: res => {
            if (res.services.length > 0) {
                    clearInterval(timer);
                    for (let i = 0; i < res.services.length; i++) {
                        if (res.services[i].isPrimary) {
				getBLEDeviceCharacteristics(deviceId, res.services[i].uuid, callBack);
				serviceId = res.services[i].uuid;
				return;
                            }
			}
		} else {
                    getBLEDeviceServices(deviceId, callBack);
            }
            }
        });
    }, 1000)
}

6.获取蓝牙特征值

function getBLEDeviceCharacteristics(deviceId, serviceId, callBack) {
	uni.getBLEDeviceCharacteristics({
		deviceId,
		serviceId,
		success: res => {
			console.log('getBLEDeviceCharacteristics success', res.characteristics);
			for (let i = 0; i < res.characteristics.length; i++) {
				let item = res.characteristics[i];
				// console.log(item.properties)
				if (item.properties.read) {
					uni.readBLECharacteristicValue({
						deviceId,
						serviceId,
						characteristicId: item.uuid
					});
				}
				if (item.properties.write) {
					characteristicId = item.uuid;
					console.log('读写数据', deviceId, serviceId, characteristicId)
				}
				if (item.properties.notify || item.properties.indicate) {
					uni.notifyBLECharacteristicValueChange({
						deviceId,
						serviceId,
						characteristicId: item.uuid,
						state: true
					});
				}
			}
		},
		fail(res) {
			console.error('getBLEDeviceCharacteristics err', res);
		}
	});
	uni.onBLECharacteristicValueChange(characteristic => {
		//自己的操作
		let value = ab2hex(characteristic.value);
		// console.log('自己的操作', value)
		//监听设备信号强度
		listenRSSI();
		//衔接成回调函数
		if (callBack) {
			callBack();
		}
	});
	uni.onBLEConnectionStateChange(res => {
		// 该办法回调中可以用于处理衔接意外断开等异常状况
		console.log(`device ${res.deviceId} 设备状况改动, connected: ${res.connected}`);
		if (!res.connected) {
			openBluetoothAdapter(callBack);
		}
	});
	uni.getBluetoothDevices({
		success: res => {
			console.log('获取蓝牙设备成功:', res);
			let devices = res.devices;
		}
	})
}
// ArrayBuffer转16进度字符串示例
function ab2hex(buffer) {
	const hexArr = Array.prototype.map.call(
		new Uint8Array(buffer),
		function(bit) {
			return ('00' + bit.toString(16)).slice(-2)
		}
	)
	return hexArr.join('')
}
// ascii  转  二进制流
function asciiToArrayBuffer(str) {
	if (!str) {
		return new ArrayBuffer(0);
	}
	var buffer = new ArrayBuffer(str.length);
	// let dataView = new DataView(buffer)
	var bufView = new Uint8Array(buffer);
	for (var i = 0, strLen = str.length; i < strLen; i++) {
		bufView[i] = str.charCodeAt(i);
	}
	return buffer;
}
//超出信号强度外报警
function outcallDo() {
	let userInfo = uni.getStorageSync('userInfo');
	if (userInfo.nearremind != '1') {
		if (rssiTimer) {
			clearInterval(rssiTimer)
		}
		uni.showToast({
			icon: 'none',
			title: '超出范围已建议报警'
		})
		writeBLECharacteristicValue();
		let time = 10;
		let timercall = setInterval(() => {
			time--;
			if (time == 0 || time < 0) {
				clearInterval(timercall);
				listenRSSI();
			}
		}, 1000)
	}
}
function listenRSSI() {
	// 监听设备信号强度
	if (rssiTimer) {
		clearInterval(rssiTimer)
	}
	rssiTimer = setInterval(() => {
		uni.getBLEDeviceRSSI({
			deviceId: deviceId,
			success: (res) => {
				console.log('设备信号强度', res)
				uni.showToast({
					icon: 'none',
					title: '信号强度:' + res.RSSI
				})
				let saveRssi = uni.getStorageSync('saveRssi');
				console.log('saveRssi', saveRssi)
				saveRssi ? rssi = saveRssi : '';
				if (rssi == 1) {
					if (res.RSSI < -60) {
						//报警
						outcallDo();
					}
				} else if (rssi == 2) {
					if (res.RSSI < -70) {
						//报警
						outcallDo();
					}
				} else if (rssi == 3) {
					if (res.RSSI < -76) {
						//报警
						outcallDo();
					}
				}
			}
		})
	}, 1000)
}

7.超出信号强度外报警

function outcallDo() {
	let userInfo = uni.getStorageSync('userInfo');
	if (userInfo.nearremind != '1') {
		if (rssiTimer) {
			clearInterval(rssiTimer)
		}
		uni.showToast({
			icon: 'none',
			title: '超出范围已建议报警'
		})
		writeBLECharacteristicValue();
		let time = 10;
		let timercall = setInterval(() => {
			time--;
			if (time == 0 || time < 0) {
				clearInterval(timercall);
				listenRSSI();
			}
		}, 1000)
	}
}
function listenRSSI() {
	// 监听设备信号强度
	if (rssiTimer) {
		clearInterval(rssiTimer)
	}
	rssiTimer = setInterval(() => {
		uni.getBLEDeviceRSSI({
			deviceId: deviceId,
			success: (res) => {
				console.log('设备信号强度', res)
				uni.showToast({
					icon: 'none',
					title: '信号强度:' + res.RSSI
				})
				let saveRssi = uni.getStorageSync('saveRssi');
				console.log('saveRssi', saveRssi)
				saveRssi ? rssi = saveRssi : '';
				if (rssi == 1) {
					if (res.RSSI < -60) {
						//报警
						outcallDo();
					}
				} else if (rssi == 2) {
					if (res.RSSI < -70) {
						//报警
						outcallDo();
					}
				} else if (rssi == 3) {
					if (res.RSSI < -76) {
						//报警
						outcallDo();
					}
				}
			}
		})
	}, 1000)
}

8.暴露公共办法

//发送指令 蓝牙呼叫
export function writeBLECharacteristicValue(callBack) {
	console.log('deviceId:' + deviceId)
	console.log('serviceId:' + serviceId)
	console.log('characteristicId:' + characteristicId)
	// 向蓝牙设备发送一个0x00的16进制数据
	const buffer = asciiToArrayBuffer(JSON.stringify({
		'fn': '3'
	}));
	uni.writeBLECharacteristicValue({
		deviceId: deviceId, // 这儿的 deviceId 需要在 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
		serviceId: serviceId, // 这儿的 serviceId 需要在 getBLEDeviceServices 接口中获取
		characteristicId: characteristicId, // 这儿的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
		value: buffer, // 这儿的value是ArrayBuffer类型
		success(res) {
			uni.showToast({
				icon: 'none',
				title: '已建议呼叫'
			});
			if (callBack) {
				callBack(0);
			}
		},
		fail(res) {
			console.log('writeBLECharacteristicValue fail', res);
			//衔接成回调函数
			if (callBack) {
				callBack(1);
			}
		}
	});
}
/* 
	@eptName 设备称号
	@callBack() 回调函数
 */
export function blueToothLink(eptName, callBack) {
	deviceName = eptName;
	openBluetoothAdapter(callBack);
}