uni微信小程序实现蓝牙连接设备

本文将详细介绍如何在uni-app小程序中集成和使用蓝牙功能。我们将从蓝牙的基本概念出发,逐步带领大家了解连接和操作蓝牙设备,同时分享一些实用的代码实例和注意事项,帮助开发者快速上手蓝牙开发。

具体实现思路如下:

1、因为安卓和ios的差异,安卓手机在使用wx小程序蓝牙功能时,需要在页面初始化时先打开GPS定位。

2、初始化蓝牙模块--openBluetoothAdapter。

3、定义设备搜索任务,开始搜寻附近的蓝牙外围设备--startBluetoothDevicesDiscovery,这里定义一个定时器,间隔一秒去搜索,在规定的时间内,未搜索到设备提示超时。清除定时器,调用停止搜索api暂停搜索。

4、搜索到设备时,调用getBluetoothDevices方法将搜索到所有设备存储到变量集合中去,再在页面中将搜索到设备信息以列表的形式展示出来。

5、获取设备服务uuid,连接设备,蓝牙设备不能被多次连接,所以需要在每次连接前关闭BLE连接。

6、获取设备特征值进行读写操作(notify:读,write:写)。

实现代码如下:

html部分

<template>
	<view>
		<view class="search_button" @click="searchBlueToothDevice">
			开始搜索蓝牙设备
		</view>
		<view class="search_button" @click="stopBlueToothDevice">
			停止搜索蓝牙设备
		</view>
		<view v-if="state?.deviceList && state?.deviceList?.length != 0" v-for="(item, index) in state?.deviceList"
			:key="index">
			<div class="list-item" @click="connectBlueTooth(item)">
				{{ item?.localName }}
				{{ item?.deviceId }}
			</div>
		</view>
		<view type="primary" @click="
		        () =>
		          sendData(
		            state?.currentDeviceId,
		            state?.currentServiceId,
		            state?.currentCharId
		          )
		      " class="search_button">
			发送数据
		</view>

		<view v-for="(item, index) in state?.dataList" :key="index"
			v-if="state?.dataList && state?.dataList?.length != 0">
			{{ item }}
		</view>
	</view>
</template>

<style lang="scss" scoped>
	.search_button {
		width: 50%;
		background: greenyellow;
		font-size: 32rpx;
		text-align: center;
		height: 100rpx;
		line-height: 100rpx;
		margin: 20rpx auto;
	}
</style>

js实现部分

<script lang="ts" setup>
	import { onMounted, reactive } from 'vue';
	import { ab2hex, string2buffer } from "./function";

	const state = reactive<any>({
		nDelayTimer: -1, //定时器
		isFind: false, //是否发现设备
		deviceList: [], //设备列表

         //特征值
		currentDeviceId: undefined, 
		currentServiceId: undefined,
		currentCharId: undefined,

		dataList: [],
	});

	function isNotEmptyObject(obj) {
		// 检查是否为对象,并且不是 null
		if (typeof obj === 'object' && obj !== null) {
			// 使用 Object.keys 判断对象属性个数是否大于 0
			return Object.keys(obj).length > 0;
		}
		return false; // 不是对象或者是 null,返回 false
	}

	onMounted(() => {

		uni.startWifi({
			success: (res) => {
				uni.getConnectedWifi({
					success: (result) => {
						console.log(result);
					},
					fail: (result) => {
						console.log(result);
						if (result.errCode === 12006) {
							uni.showModal({
								title: "请打开GPS定位",
								content: "Android手机不打开GPS定位,无法搜索到蓝牙设备",
								showCancel: false,
							})

						} else {
							uni.showToast({
								title: `${result.errCode}`,
								icon: "none",
								duration: 2000,
							})
						}
					}
				})
			}
		});
	});

	/**
	 * @Description: 搜索蓝牙设备
	 */
	const searchBlueToothDevice = () => {
		initBlueTooth();
	};

	/**
	 * @Description: 停止搜索蓝牙设备
	 */
	const stopBlueToothDevice = () => {
		uni.hideLoading();
		clearInterval(state.nDelayTimer);
	};


	//初始化蓝牙适配器
	const initBlueTooth = () => {
		console.log("初始化蓝牙适配器");
		uni.openBluetoothAdapter({
			success: (res) => {
				console.log(res);
				findBlueTooth();
			},
			fail: (res) => {
				console.log(res);
				uni.showToast({
					title: "请先打开蓝牙",
					icon: "none",
					duration: 2000,
				});
			},
		});
	};

	//定义搜索设备任务
	const findBlueTooth = () => {
		uni.startBluetoothDevicesDiscovery({
			allowDuplicatesKey: false,
			interval: 0,
			success: (res) => {
				console.log(res);
				uni.showLoading({
					title: "正在搜索设备"
				});
				const nTimer = setInterval(() => discoveryBlueTooth(), 1000);
				state.nDelayTimer = nTimer;
				setTimeout(() => {
					uni.hideLoading();
					if (state.isFind) {
						return;
					}
					console.log("搜索设备超时");
					uni.stopBluetoothDevicesDiscovery({
						success: (result) => {
							console.log(result);
						},
					});
					clearInterval(state.nDelayTimer);
					uni.showModal({
						title: "搜索设备超时",
						content: "请检查蓝牙设备是否正常工作,Android手机请打开GPS定位",
						showCancel: false,
					});
				}, 15000);
			},
			fail: (res) => {
				console.log(res);
				uni.showToast({
					title: `蓝牙设备服务发现设备${res.errMsg}`,
					icon: "none",
					duration: 2000,
				})
			}
		})
	}
	//搜索设备回调方法
	const discoveryBlueTooth = () => {
		uni.getBluetoothDevices({
			success: (res) => {
				console.log("🚀 ~ discoveryBlueTooth ~ res:", res);
				if (res?.devices && res?.devices?.length != 0) {
					const list = res.devices;
					const devices : any[] = [];
					list.forEach((item) => {
						const name = item.localName || item.name;
						if (isNotEmptyObject(name) && name !== "" && name !== "未知设备") {
							devices.push(item);
						}
					});
					console.log("🚀 ~ discoveryBlueTooth ~ devices:", devices);

					state.deviceList = devices;
					state.isFind = true;
				}
			},
			fail: (res) => {
				console.log(res);
				uni.showToast({
					title: "搜索蓝牙设备失败",
					icon: "none",
					duration: 2000,
				});
			},
		});
	}

	//连接蓝牙设备
	const connectBlueTooth = (device : any) => {
		uni.showLoading({ title: "开始连接设备" });
		closeBlueTooth(device, () => {
			setTimeout(() => {
				uni.createBLEConnection({
					deviceId: device?.deviceId,
					success: (res : any) => {
						uni.hideLoading();
						uni.showToast({
							title: "设备连接成功",
							icon: "success",
							duration: 2000,
						});
						console.log(res);
						getBlueToothService(device?.deviceId);
					},
					fail: (res : any) => {
						uni.hideLoading();
						uni.showToast({
							title: `设备连接失败:${res.errMsg}`,
							icon: "none",
							duration: 2000,
						});
						console.log(res);
					},
				});
			}, 2000);
		});
	};

	//关闭蓝牙设备(手机端可以同时连接多个蓝牙设备,但是同一个蓝牙设备不能被多次连接,所以需要在每次连接前关闭BLE连接)
	const closeBlueTooth = (device : any, callback : any) => {
		uni.closeBLEConnection({
			deviceId: device?.deviceId,
			success: (res : any) => {
				console.log(`断开蓝牙设备[${device?.deviceId}]成功`);
				console.log(res);
			},
			fail: (res : any) => {
				console.log(res);
			},
			complete: callback,
		});
	};

	//获取蓝牙设备服务uuid
	const getBlueToothService = (deviceId : any) => {
		uni.getBLEDeviceServices({
			deviceId: deviceId,
			success: (res : any) => {
				console.log(res);
				const services = res.services;
				if (services.length <= 0) {
					console.log("未找到主服务列表");
					return;
				}
				console.log(`找到服务列表个数:${services.length}`);
				const service = services[0];
				console.log(`服务UUID:${service.uuid}`);
				getBlueToothCharacteristics(deviceId, service.uuid);
			},
			fail: (res : any) => {
				console.log(`获取服务列表失败:${res.errMsg}`);
			},
		});
	}

	//获取设备特征值
	const getBlueToothCharacteristics = (deviceId : any, uuid : any) => {
		uni.getBLEDeviceCharacteristics({
			deviceId: deviceId,
			serviceId: uuid,
			success: (res : any) => {
				console.log(res);
				// 这里会获取到两个特征值,一个用来写,一个用来读
				const chars = res.characteristics;
				if (chars.length <= 0) {
					console.log("未找到设备特征码");
					return;
				}
				console.log(`找到设备特征码个数:${chars.length}`);
				if (chars.length >= 2) {
					chars.forEach((item : any) => {
						const prop = item.properties;
						if (prop.notify === true) {
							receiveData(deviceId, uuid, item.uuid);
						} else if (prop.write === true) {
							sendData(deviceId, uuid, item.uuid);
							state.currentDeviceId = deviceId;
							state.currentServiceId = uuid;
							state.currentCharId = item.uuid;
						}
					});
				}

			},
			fail: (res) => {
				console.log(`获取设备特征码失败:${res.errMsg}`);
			}
		});


	}

	//接受蓝牙设备发送过来的数据
	const receiveData = (deviceId : any, serviceId : any, charId : any) => {
		uni.notifyBLECharacteristicValueChange({
			deviceId: deviceId,
			serviceId: serviceId,
			characteristicId: charId,
			state: true,
			success: (res : any) => {
				console.log(res);
				uni.onBLECharacteristicValueChange((data : any) => {
					console.log(data);
					const value = ab2hex(data.value);
					console.log(`收到Notify数据:${value}`);
					let list : any[] = state.dataList;
					list.push(value);
					state.dataList = list;
				});
			},
			fail: (res : any) => {
				console.log(`特征值Notice 接收数据失败:${res.errMsg}`);
			},
		});
	};

	//向蓝牙设备发送数据
	const sendData = (deviceId : any, serviceId : any, charId : any) => {
		const str = "111";
		const buffer = string2buffer(str);
		console.log(buffer);
		setTimeout(() => {
			uni.writeBLECharacteristicValue({
				value: buffer,
				deviceId: deviceId,
				serviceId: serviceId,
				characteristicId: charId,
				success: (res : any) => {
					console.log(res);
					console.log(`发送成功`);
				},
				fail: (res : any) => {
					console.log(`发送失败:${res.errMsg}`);
				},
			});
		}, 1000);
	}
</script>

字符串转换方法

//将ArrayBuffer转换成字符串
export const ab2hex = (buffer: any) => {
    var hexArr = Array.prototype.map.call(
      new Uint8Array(buffer),
      function (bit: any) {
          return ('00' + bit.toString(16)).slice(-2)
      }
    );
    return hexArr.join('');
}

// 将字符串转换成ArrayBufer
export const string2buffer = (str: string) : ArrayBuffer => {
  if (!str) return new ArrayBuffer(0);
  let length = str.length;
  let index = 0;
  let array: any = []
  while (index < length) {
    array.push(str.substring(index, index + 2));
    index = index + 2;
  }
  const val = array.join(",");
  console.log(val);
  return new Uint8Array(array.map(function (h) {
    return parseInt(h, 16)
  })).buffer;
 }

希望能对您起到帮助,国庆快乐!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值