uniapp 微信小程序 支付宝小程序 蓝牙选择连接

1:新建一个vue页面 index.vue

<template>
<view>

<view class="list" v-if="isHaveDevice">
</view>

		<view class="" v-else>

			<!-- 搜索中 -->
			<view class="ks" v-if="state==1">
				<view class="img">
					<image src="https://beoka-file.oss-cn-beijing.aliyuncs.com/beoka_oxy/img/1000001900587011.gif">
					</image>
				</view>
				<view class="searchText">
					蓝牙搜索中...
				</view>

			</view>
			<!-- 搜索失败 -->
			<view class="fail" v-if="state==3">
				<view class="img">
					<image src="@/static/none.png"></image>
				</view>
				<view class="text">
					搜索失败
				</view>

			</view>
			<view class="zy">
				<view class="title">
					注意:
				</view>
				<view class="text">
					<span>
						1、
					</span>
					<p>
						请保持设备为开机状态;
					</p>
				</view>
			
			
		

			</view>

		</view>
		<view class="btns" v-show="state==3" >
			<!-- <view class="clear" @click="clickClear">
				取消
			</view> -->
			<view class="comfirm" @click='clickRetry'>
				再次搜索
			</view>
		</view>
	</view>
</template>

<script>
	import bluetooth from '@/uilts/boxYj.js';
	import {
		deviceInfoApi
	} from "@/api/device.js"
	export default {
		data() {
			return {
				state: 1,
				deviceNo: '',
				orderNo: "",
				stateText: '未连接',
				bluetoothStatus: false, // 蓝牙连接状态
				bluetoothName: 'Hi-S6-A-',  Hi-S6-A-//蓝牙名字
				buffer: '', //下发数据
				devicesList: [], //蓝牙列表
				isHaveDevice: false, //是否搜到设备
				time: 0,
				timer: null
			}
		},
		onLoad() {
			// 搜索蓝牙
			this.initBluetooth();
			

		},
		onShow() {
			this.devicesList=[]
		},
		onUnload() {
			console.log('页面卸载,执行一些清理工作');
			bluetooth.closeBlec().then(res => {
				console.log('断开蓝牙', res);
			})
		},
		methods: {


			// 立即重试
			clickRetry() {
				
				let _this = this
				_this.devicesList=[]
				_this.state = 1
				_this.isHaveDevice = false
				clearInterval(_this.timer)
				_this.timer = null
				_this.time = 0
				if (!_this.timer) {
					this.initBluetooth()
				}

			},

			// 绑卡
			clickBild(item) {
				uni.showLoading({
					title: '获取盒子信息中...',
					icon: 'none'
				})
				this.bluetoothConnect(item, () => {
					let _this = this
					//1 10进制的需求   2  组装下发  16进制
					
					// let num = this.$config.IntToBytesLittleEndian(43000, 2)
					let v = ["BB", "66", "06", "01", '01']; //命令数据表示16进制 
					//转16进制
					let list = [...this.$config.parseInt(v)]
					console.log(v, list, '---');
					// 10进制转换
					let buffer = this.$config.arr2ab(list)
					if (this.bluetoothStatus) {
						_this.writeBlueData(buffer, '获取数据成功', 1)
					}
				})

			},

			// 开锁并向设备发送命令开锁
			open(item) {
				uni.showLoading({
					title: '开锁中...',
					icon: 'none'
				})
				this.bluetoothConnect(item, () => {
					let _this = this
					//1 10进制的需求   2  组装下发  16进制
				
					// let num = this.$config.IntToBytesLittleEndian(43000, 2)
					let v = ["BB", "66", "01", "01", '01']; //命令数据表示16进制 
					//转16进制
					let list = [...this.$config.parseInt(v)]
					console.log(v, list, '---');
					// 10进制转换
					let buffer = this.$config.arr2ab(list)
					if (this.bluetoothStatus) {
						_this.writeBlueData(buffer, '开锁成功', 0)
					}
				})


			},
			// 向设备发送数据
			writeBlueData(buffer, title, type) {
				let _this = this
				_this.$store.state.type = type || 0;
				bluetooth.writeData(buffer).then(res => {
					uni.hideLoading()
					_this.bluetoothStatus = false // 蓝牙连接状态

					uni.showToast({
						title: title || '操作成功',
						icon: 'none'
					})

				}).catch(err => {
					_this.state = 3
				})
			},


			// 点击连接
			bluetoothConnect(item, callBack) {
				var _this = this;
				clearInterval(_this.timer)
				_this.timer = null
				_this.time = 0

				bluetooth.closeBlec().finally(res => {
					console.log('断开蓝牙', res);
					setTimeout(() => {
						bluetooth.connectBluetooth(item).then((
							bluetoothConnect) => {
							console.log('连接成功');
							setTimeout(() => {
								_this.stateText = '连接成功'
								_this.bluetoothStatus = true;
								callBack()
							}, 1000)

							// 监听蓝牙与设备连接状态
							bluetooth.BLECStateChange().then(res => {
								_this.bluetoothStatus = res.connected
								_this.stateText = '未连接'
								console.log(res, '监听设备连接状态');
							})
						}).catch((err) => {
							uni.showToast({
								title: '开锁失败',
								icon: 'none'
							})
							_this.bluetoothStatus = false;
							_this.deviceState = false
							_this.state = 3
							// #ifdef MP-ALIPAY
							uni.hideLoading();
							// #endif

						})
					},2000)


				})


			},
			// 获取蓝牙和设备
			initBluetooth() {
				let _this = this
				// 初始化蓝牙
				bluetooth.getBluetoothState().then(() => {
					// 搜索外围蓝牙设备
					bluetooth.discoveryBluetooth().then(() => {
						_this.discoveryLoading = true;
						// 获取蓝牙设备
						_this.timer = setInterval(() => {
							if (_this.time <= 30) {
								bluetooth.getBluetoothDevices(this.bluetoothName).then((res) => {
									console.log(res, '回调', this.bluetoothName);
									++this.time
									if (res.isHaveDevice) {
										_this.isHaveDevice = res.devices.length ? true :
											false
										_this.devicesList = res.devices
										_this.state = res.devices.length ? 3 :
											1
									} else {
										// 未搜到设备
										this.isHaveDevice = false
										_this.bluetoothStatus = false;
										_this.deviceState = false
										_this.state = 3
										_this.devicesList = res.devices
										clearInterval(_this.timer)
										_this.timer = null
										_this.time = 0


									}
								}).catch((err) => {
									this.isHaveDevice = false
									_this.devicesList = err.devices
									// 蓝牙搜索失败
									_this.bluetoothStatus = false;
									_this.deviceState = false
									_this.state = 3
									clearInterval(_this.timer)
									_this.timer = null
									_this.time = 0
								});
							} else {
								this.isHaveDevice = _this.devicesList.length ? true : false
								_this.state = 3
								clearInterval(_this.timer)
								_this.timer = null
								this.time = 0
							}
						}, 1000)

					});

				}).catch((err) => {
					// 未开启蓝牙

					_this.bluetoothStatus = false;
					_this.deviceState = false
					_this.state = 3
				});
			},
			// 返回
			leftClick() {
				var _this = this;
				clearInterval(_this.timer)
				_this.timer = null
				_this.time = 0
				bluetooth.closeBlec()
				uni.navigateBack()

			},
			// 取消
			clickClear() {
				var _this = this;
				clearInterval(_this.timer)
				_this.timer = null
				_this.time = 0
				bluetooth.closeBlec()
				uni.showToast({
					title: '取消成功',
					icon: 'none'
				})
			},
		}
	}
</script>

<style lang="less">
	page {
		background-color: #f4f4f8;
	}

	.list {
		padding: 24rpx;
		box-sizing: border-box;

		.item {
			width: 100%;
			height: 230rpx;
			padding: 32rpx;
			box-sizing: border-box;
			background: #ffffff;
			border-radius: 24rpx;
			display: flex;
			margin-bottom: 32rpx;

			.img {
				width: 190rpx;
				height: 166rpx;
				border-radius: 16rpx;
				overflow: hidden;

				image {
					width: 100%;
					height: 100%;
				}
			}

			.info {
				flex: 1;
				margin-left: 32rpx;
				display: flex;
				flex-direction: column;
				justify-content: space-between;

				.name {
					font-size: 32rpx;
					font-family: PingFang HK, PingFang HK-500;
					font-weight: 500;
					text-align: LEFT;
					color: #333333;
					line-height: 38rpx;
				}

				.code {
					font-size: 28rpx;
					font-family: PingFang HK, PingFang HK-400;
					font-weight: 400;
					text-align: LEFT;
					color: #969696;
					line-height: 32rpx;
				}

				.kg {
					display: flex;
					font-size: 24rpx;
					font-family: PingFang HK, PingFang HK-400;
					font-weight: 400;
					text-align: CENTER;
					color: #ffffff;
					line-height: 60rpx;

					.open {
						width: 150rpx;
						height: 60rpx;
						background: #f98518;
						border: 2rpx solid #f98518;
						border-radius: 70rpx;
					}

					.car {
						width: 150rpx;
						height: 60rpx;
						border: 2rpx solid #bdbdbd;
						border-radius: 70rpx;
						color: #333;
						margin-left: 32rpx;
					}

					.sx {
						width: 150rpx;
						height: 60rpx;
						background: #d2d2d2;
						border-radius: 70rpx;
						margin-left: 32rpx;
						border: 2rpx solid #d2d2d2;
					}
				}
			}
		}
	}

	.ks {
		margin: 35rpx auto 0;
		display: flex;
		flex-direction: column;
		justify-content: center;
		align-items: center;

		.img {
			width: 460rpx;
			height: 460rpx;

			image {
				width: 100%;
				height: 100%;
			}
		}

		.searchText {
			text-align: center;
			font-size: 24rpx;
			font-family: PingFang HK, PingFang HK-400;
			font-weight: 400;
			color: rgba(0, 0, 0, 0.20);
			line-height: 28rpx;
		}
	}


	.fail {
		margin: 166rpx auto 0;
		display: flex;
		flex-direction: column;
		justify-content: center;
		align-items: center;

		.img {
			width: 208rpx;
			height: 186rpx;

			image {
				width: 100%;
				height: 100%;
			}
		}

		.text {
			font-size: 24rpx;
			font-family: PingFang HK, PingFang HK-400;
			font-weight: 400;
			text-align: LEFT;
			color: rgba(0, 0, 0, 0.20);
			line-height: 28rpx;
			margin: 46rpx 0 64rpx;
		}

		.btn {
			width: 512rpx;
			height: 96rpx;
			line-height: 96rpx;
			background: #192006;
			border-radius: 100rpx;
			text-align: center;
			font-size: 28rpx;
			font-family: PingFang HK, PingFang HK-400;
			font-weight: 400;
			text-align: CENTER;
			color: #FFFFFF;
			//letter-spacing: 0.2rpx;
		}
	}


	.zy {
		margin: 25% 0 0 112rpx;

		.title {
			font-size: 28rpx;
			font-family: PingFang HK, PingFang HK-400;
			font-weight: 400;
			text-align: LEFT;
			color: #333333;
			line-height: 32rpx;
			margin-bottom: 16rpx;
		}

		.text {
			font-size: 26rpx;
			font-family: PingFang HK, PingFang HK-400;
			font-weight: 400;
			text-align: LEFT;
			color: #333333;
			line-height: 48rpx;
			display: flex;
			margin-bottom: 10rpx;

			p {
				width: 80%;
			}
		}

	}

	.btns {
		background-color: #fff;
		position: fixed;
		bottom: 0;
		left: 0;
		width: 100%;
		height: 160rpx;
		align-items: center;
		display: flex;
		align-items: center;
		justify-content: center;
		border-radius: 40rpx 40rpx 0rpx 0rpx;
		box-shadow: 0px -8rpx 112rpx 0rpx rgba(125, 130, 139, 0.08);

		.clear,
		.comfirm {
			width: 94%;
			height: 96rpx;
			line-height: 96rpx;
			border-radius: 128rpx;
			font-size: 28rpx;
			font-family: PingFang HK, PingFang HK-400;
			font-weight: 400;
			text-align: CENTER;
			color: #333333;
			//letter-spacing: 2rpx;
			box-sizing: border-box;
		}

		.clear {
			border: 2rpx solid #DCE4F0;
			color: #9AA1B8;
		}

		.comfirm {
			background-color: #F98518;
			color: #fff;
		}
	}
</style>

2: 创建boxYj.js 

// import { TextDecoder } from 'text-encoding-utf-8';
import store from '../store';
let bluetoothOpen = false; // 手机蓝牙是否打开
let bluetoothConnect = false; // 设备和蓝牙是否连接
let isHaveDevice = false; // 是否查找到设备
let deviceId = null; // 设备id
let serviceId = null; // 服务id
let notify = null; // 监听uuid
let writeId = null; // 写入uuid
let dataList = []
let platform = ''
/**
 * 获取手机蓝牙是否打开
 */
const getBluetoothState = () => {
	// 主机模式
	return new Promise((resolve, reject) => {
		// mode: 'central',
		uni.openBluetoothAdapter({
			success: (r) => {
				console.log("蓝牙初始化成功");
				// 获取蓝牙的匹配状态
				uni.getBluetoothAdapterState({
					success: function(row) {
						console.log('蓝牙状态:', row.available);
						if (row.available) {
							bluetoothOpen = true;
							getLocation().then(res => {
								console.log('4444');
								resolve();
							}).catch(err => {
								bluetoothOpen = false;
								bluetoothConnect = false;
								reject();
							})

						} else {
							// 请开启蓝牙
							uni.showToast({
								title: '请打开蓝牙',
								icon: 'none'
							})
							bluetoothOpen = false;
							bluetoothConnect = false;

							reject();
						}
					},
					fail: function(err) {
						// 请开启蓝牙
						uni.showToast({
							title: '请打开蓝牙',
							icon: 'none'
						})
						bluetoothOpen = false;
						bluetoothConnect = false;
						reject();
					}
				})
			},
			fail: (err) => {
				// 请开启蓝牙
				console.log('蓝牙初始化失败', err);
				if (err.errno == 103) {
					uni.showModal({
						title: '温馨提示',
						content: '您已拒绝授权,是否去设置打开?',
						confirmText: "确认",
						cancelText: "取消",
						success: function(res) {
							// console.log(res);
							if (res.confirm) {
								uni.openSetting({
									success: (res) => {
										console.log(res, '设置');
										// res.authSetting[scope] = true
										// resolve()
									}
								});
							}
						},

					});
				} else if (err.errCode == 10001) {

					uni.showToast({
						title: '请前往手机设置,打开此APP蓝牙权限',
						icon: 'none'
					})

				} else {
					uni.showToast({
						title: '请打开手机蓝牙',
						icon: 'none'
					})
				}
				bluetoothOpen = false;
				bluetoothConnect = false;
				reject();
			}
		});
	});
};
/**
 * 开始搜索蓝牙设备
 */
const discoveryBluetooth = () => {
	return new Promise((resolve) => {
		uni.startBluetoothDevicesDiscovery({
			success(res) {
				console.log('搜索蓝牙外围设备完成', res)

				setTimeout(() => {
					resolve();
				}, 2000);
			}
		});
	})
};
// 关闭蓝牙搜索
const stopDiscoveryBluetooth = () => {
	uni.stopBluetoothDevicesDiscovery({
		success(r) {
			console.log("停止搜索蓝牙设备", r);
		}
	});
};




/**
 * 获取搜索到的设备信息
 */
const getBluetoothDevices = (deviceName) => {
	return new Promise((resolve, reject) => {
		uni.getBluetoothDevices({
			success(res) {
				bluetoothConnect = false;
				// 过滤掉name为空或者未知设备的设备
				let devices = res.devices.filter(function(obj) {
					return obj.name !== "" && obj.name !== "未知设备" && obj.name.substring(0,
						8) == deviceName
				});
				// console.log('有名称蓝牙列表1', devices);
				console.log(devices, '蓝牙1', deviceName);
				isHaveDevice = true;
				resolve({
					isHaveDevice,
					devices
				});



			},
			fail: function() {
				console.log('搜索蓝牙设备失败');
				bluetoothConnect = false;
				isHaveDevice = false;
				reject({
					isHaveDevice,
					devices: []
				});
			}

		});
	});
};

/**
 * 连接蓝牙
 * deviceId 蓝牙设备id
 */
const connectBluetooth = (item) => {
	deviceId = item.deviceId
	return new Promise((resolve, reject) => {
		uni.createBLEConnection({
			deviceId: deviceId, // 设备id
			success() {
				bluetoothConnect = true;
				if (platform == 'android') {
					// 修改蓝牙MTU值
					uni.setBLEMTU({
						deviceId: deviceId,
						mtu: 200,
						success: (res) => {
							console.log(res, 'mtu设置成功传输最大值');
						},
						fail: (res) => {
							console.log(res, 'mtu设置失败');
						},
					});

				}

				console.log('连接蓝牙成功', deviceId);
				// 蓝牙连接成功后关闭蓝牙搜索
				stopDiscoveryBluetooth();
				// 获取服务id
				getServiceId();
				setTimeout(() => {
					resolve();
				})
			},
			fail(err) {
				bluetoothConnect = false;
				console.log("蓝牙连接失败", err);
				reject();
			}
		});
	});
};
// 获取服务id
const getServiceId = () => {
	uni.getBLEDeviceServices({
		deviceId: deviceId,
		success(res) {
			console.log(res.services, '服务id成功');
			// 方案一
			res.services.forEach(item => {
				let firstFive = ''

				firstFive = item.uuid.substring(0, 8);
				var FFF0 = /fff0/i;
				console.log(firstFive, 'firstFive');
				if (FFF0.test(firstFive)) {
					serviceId = item.uuid;
					// 调用蓝牙监听和写入功能
					getCharacteId();
				}
			});



		},
		fail(err) {
			console.log('获取服务失败', err);
		}
	})
};
// 获取蓝牙低功耗设备某个服务中所有特征
const getCharacteId = () => {
	uni.getBLEDeviceCharacteristics({
		deviceId: deviceId, // 蓝牙设备id
		serviceId: serviceId, // 蓝牙服务UUID
		success(res) {
			console.log('数据监听', res);
			res.characteristics.forEach(item => {
				let firstFive = ''
				// #ifdef MP-WEIXIN
				firstFive = item.uuid.substring(0, 8);
				// #endif
				// #ifdef MP-ALIPAY
				firstFive = item.characteristicId.substring(0, 8);
				// #endif

				console.log(firstFive, 'firstFive');
				var FFF1 = /fff1/i;
				var FFF2 = /fff2/i;

				// 001
				if (item.properties.notify === true && FFF1.test(firstFive)) {
					// 监听
					// 微信
					// #ifdef MP-WEIXIN
					notify = item.uuid;
					// #endif

					//支付宝
					// #ifdef MP-ALIPAY
					notify = item.characteristicId;
					// #endif
					startNotice();
				}
				// 002
				if (item.properties.write === true && FFF2.test(firstFive)) {
					// 写入 
					// 微信
					// #ifdef MP-WEIXIN
					let writeId = item.uuid;
					uni.setStorageSync("writeId", item.uuid);

					// #endif

					//支付宝
					// #ifdef MP-ALIPAY
					let writeId = item.serviceId;
					uni.setStorageSync("writeId", item.characteristicId);
					// #endif


				}
			});
		},
		fail(err) {
			console.log("数据监听失败", err)
		}
	})
};
// 启用低功耗蓝牙设备特征值变化时的notify功能
const startNotice = () => {
	uni.notifyBLECharacteristicValueChange({
		characteristicId: notify,
		deviceId: deviceId,
		serviceId: serviceId,
		state: true,
		success(res) {
			// 监听低功耗蓝牙设备的特征值变化
			uni.onBLECharacteristicValueChange(result => {
				console.log("监听低功耗蓝牙设备的特征值变化", result);
				if (result.value) {
					// let decoder = new TextDecoder('utf-8');
					// let data = decoder.decode(result.value);
					// let data = result.value;
					dataList = ab2hex(result.value)
					let info = {
						deviceId,
						dataList
					}
					let type = store.state.type
					console.log(dataList, '帽子返回数据', type)
					if (type == 1) {
						uni.navigateTo({
							url: '/pagesB/bindCar/bindCar?info=' + JSON.stringify(info)
						})
					} else if (type == 2) {
						console.log('我在绑卡', type);
						store.state.cardCodeLsit = dataList
					} else if (type == 3) {
						store.state.bindCardState = true
					}


				}
			})
		}
	});
};




// 蓝牙发送数据
const writeData = (buffer) => {

	return new Promise((resolve, reject) => {
		console.log(uni.getStorageSync("writeId"), '下发命令1writeId');
		console.log(deviceId, '下发命令2deviceId');
		console.log(serviceId, '下发命令3serviceId');
		console.log(buffer, '下发命令4buffer');

		uni.writeBLECharacteristicValue({
			characteristicId: uni.getStorageSync("writeId"),
			deviceId: deviceId,
			serviceId: serviceId,
			value: buffer,
			success(res) {
				console.log("writeBLECharacteristicValue success", res);
				resolve();
			},
			fail(err) {
				console.log("报错了", err);
				reject();
			}
		});
	});
};

// 读取数据并解析
const ab2hex = (buffer) => {
	let hexArr = Array.prototype.map.call(new Uint8Array(buffer), function(
		bit
	) {
		return ("00" + bit.toString(16)).slice(-2);
	});
	return hexArr;
	// const hexArr = Array.prototype.map.call(
	// 	new Uint8Array(buffer),
	// 	function(bit) {
	// 		return ('00' + bit.toString(16)).slice(-2)
	// 	}
	// )
	// return hexArr.join('')

}

// 断开蓝牙
const closeBlec = () => {
	return new Promise((resolve, reject) => {
		uni.closeBLEConnection({
			deviceId: deviceId,
			success(res) {
				resolve();
				console.log(res, '断开成功')
			},
			fail(err) {
				reject();
				console.log("断开失败", err);
			}
		})
	})

}

// 监听蓝牙连接状态
const BLECStateChange = () => {
	return new Promise((resolve, reject) => {
		uni.onBLEConnectionStateChange(function(res) {
			store.state.blueStatu = res.connected
			// 该方法回调中可以用于处理连接意外断开等异常情况
			console.log(
				`device ${res.deviceId} state has changed, connected: ${res.connected}`)
			return resolve(res)

		})
	})

}




// 根据 ios  安卓处理不同逻辑
const getLocation = () => {
	return new Promise((resolve, reject) => {
		uni.getSystemInfo({
			success: function(info) {
				console.log('手机', info);
				if (info.platform == 'android') {
					platform = 'android'
					// 安卓手机
					console.log('1111');
					if (info.locationEnabled) {
						if (info.locationAuthorized) {
							resolve()
						} else {
							// #ifdef MP-WEIXIN
							uni.showToast({
								title: '请打开微信定位权限',
								icon: 'none'
							})
							// #endif
							// #ifdef MP-ALIPAY
							uni.showToast({
								title: '请打开支付宝定位权限',
								icon: 'none'
							})
							// #endif
							reject()
						}

					} else {
						console.log('333');
						uni.showToast({
							title: '请打开手机定位权限',
							icon: 'none'
						})
						reject()
					}

				} else {
					// 非安卓手机
					platform = 'ios'
					console.log('非安卓手机');
					resolve()
				}
			}
		});
	})

}



// 抛出方法

export default {
	getBluetoothState,
	discoveryBluetooth,
	stopDiscoveryBluetooth,
	getBluetoothDevices,
	connectBluetooth,
	getServiceId,
	getCharacteId,
	startNotice,
	writeData,
	closeBlec,
	BLECStateChange
};

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值