| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723 | <template>	<view>		<page-head :title="title"></page-head>		<view class="uni-padding-wrap uni-common-mt">			<view>				本蓝牙协议只支持低功耗蓝牙协议ble。如果想连接非ble蓝牙设备,请在社区搜索 Native.js 蓝牙。			</view>			<view class="uni-btn-v">				<button type="primary" :disabled="disabled[0]" @click="openBluetoothAdapter">					初始化蓝牙模块				</button>				<view v-if="!adapterState.available">					{{ '蓝牙适配器不可用,请初始化蓝牙模块' }}				</view>				<button					type="primary"					:loading="searchLoad"					:disabled="disabled[1]"					@click="startBluetoothDevicesDiscovery"				>					开始搜索蓝牙设备				</button>				<button					type="primary"					:disabled="disabled[2]"					@click="stopBluetoothDevicesDiscovery(false)"				>					停止搜索蓝牙设备				</button>				<button					type="primary"					:loading="newDeviceLoad"					:disabled="disabled[3]"					@click="queryDevices"				>					选择设备				</button>				<view v-if="equipment.length > 0">					{{						(connected ? '已连接设备' : '已选择设备') +							' : ' +							equipment[0].name +							' (' +							equipment[0].deviceId +							')'					}}				</view>				<button type="primary" :disabled="disabled[4]" @click="createBLEConnection">					连接蓝牙设备				</button>				<button type="primary" :disabled="disabled[5]" @click="getBLEDeviceServices">					选择设备服务				</button>				<view v-if="servicesData.length > 0">已选服务uuid:{{ servicesData[0].uuid }}</view>				<button type="primary" :disabled="disabled[6]" @click="getBLEDeviceCharacteristics">					获取服务的特征值				</button>				<view v-if="characteristicsData.length > 0">					<view class="uni-list_name">uuid:{{ characteristicsData[0].uuid }}</view>					<view class="uni-list_item">						是否支持 read 操作:{{ characteristicsData[0].properties.read }}					</view>					<view class="uni-list_item">						是否支持 write 操作:{{ characteristicsData[0].properties.write }}					</view>					<view class="uni-list_item">						是否支持 notify 操作:{{ characteristicsData[0].properties.notify }}					</view>					<view class="uni-list_item">						是否支持 indicate 操作:{{ characteristicsData[0].properties.indicate }}					</view>				</view>				<!-- <button type="primary" :disabled="disabled[7]" @click="readBLECharacteristicValue">					读取特征值数据				</button>				<view v-if="valueChangeData.serviceId">					<view class="list-name">						特征值最新的值:{{ valueChangeData.value || '还没有最新值' }}					</view>				</view> -->				<!-- <button type="primary" :disabled="disabled[8]" @click="w">写入特征值数据</button> -->				<button type="primary" :disabled="disabled[9]" @click="closeBLEConnection">					断开蓝牙设备				</button>				<button type="primary" :disabled="disabled[10]" @click="closeBluetoothAdapter">					关闭蓝牙模块				</button>			</view>		</view>		<!-- 遮罩 -->		<view v-if="maskShow" class="uni-mask" @touchmove.stop.prevent="moveHandle" @click="maskclose">			<scroll-view class="uni-scroll_box" scroll-y @touchmove.stop.prevent="moveHandle" @click.stop="moveHandle">				<view class="uni-title">					已经发现{{ list.length }}{{ showMaskType === 'device' ? '台设备' : '个服务' }}:				</view>				<view					class="uni-list-box"					v-for="(item, index) in list"					:key="index"					@click="tapQuery(item)"				>					<view v-if="showMaskType === 'device'">						<view class="uni-list_name">{{ item.name || item.localName }}</view>						<view class="uni-list_item">信号强度:{{ item.RSSI }}dBm</view>						<view class="uni-list_item">UUID:{{ item.deviceId }}</view>						<!-- <view class="list-item" v-if="showMaskType === 'device'">							Service数量:{{ item.advertisServiceUUIDs.length }}						</view> -->					</view>					<view v-if="showMaskType === 'service'">						<view class="uni-list_item" style="line-height:2.2;">							UUID: {{ item.uuid }}							<text v-if="showMaskType === 'service'">								{{ item.isPrimary ? '(主服务)' : '' }}							</text>						</view>					</view>					<view v-if="showMaskType === 'characteristics'">						<view class="uni-list_name">uuid:{{ item.uuid }}</view>						<view class="uni-list_item">是否支持 read 操作:{{ item.properties.read }}</view>						<view class="uni-list_item">							是否支持 write 操作:{{ item.properties.write }}						</view>						<view class="uni-list_item">							是否支持 notify 操作:{{ item.properties.notify }}						</view>						<view class="uni-list_item">							是否支持 indicate 操作:{{ item.properties.indicate }}						</view>					</view>				</view>			</scroll-view>		</view>	</view></template><script>export default {	data() {		return {			title: 'bluetooth',			disabled: [false, true, true, true, true, true, true, true, true, true, true],			newDeviceLoad: false,			searchLoad: false,			maskShow: false,			equipment: [],			adapterState: {				discovering: false,				available: false			},			connected: false,			showMaskType: 'device',			servicesData: [],			characteristicsData: [],			valueChangeData: {},			isStop:true ,			list: []		};	},	onLoad() {		this.onBLEConnectionStateChange();	},	methods: {		moveHandle() {},		/**		 * 关闭遮罩		 */		maskclose(){			this.maskShow = false;		},		/**		 * 选择设备		 */		queryDevices() {			// this.newDeviceLoad = true;			this.showMaskType = 'device';			this.maskShow = true;		},		tapQuery(item) {			if (this.showMaskType === 'device') {				this.$set(this.disabled, 4, false);				if (this.equipment.length > 0) {					this.equipment[0] = item;				} else {					this.equipment.push(item);				}				this.newDeviceLoad = false;			}			if (this.showMaskType === 'service') {				this.$set(this.disabled, 6, false);				if (this.servicesData.length > 0) {					this.servicesData[0] = item;				} else {					this.servicesData.push(item);				}			}			if (this.showMaskType === 'characteristics') {				this.$set(this.disabled, 7, false);				if (this.characteristicsData.length > 0) {					this.characteristicsData[0] = item;				} else {					this.characteristicsData.push(item);				}			}			this.maskShow = false;		},		/**		 * 初始化蓝牙设备		 */		openBluetoothAdapter() {			uni.openBluetoothAdapter({				success: e => {					console.log('初始化蓝牙成功:' + e.errMsg);					console.log(JSON.stringify(e));					this.isStop = false ;					this.$set(this.disabled, 0, true);					this.$set(this.disabled, 1, false);					this.$set(this.disabled, 10, false);					this.getBluetoothAdapterState();				},				fail: e => {					console.log(e)					console.log('初始化蓝牙失败,错误码:' + (e.errCode || e.errMsg));					if (e.errCode !== 0) {						initTypes(e.errCode,e.errMsg);					}				}			});		},		/**		 * 开始搜索蓝牙设备		 */		startBluetoothDevicesDiscovery() {			uni.startBluetoothDevicesDiscovery({				success: e => {					console.log('开始搜索蓝牙设备:' + e.errMsg);					this.searchLoad = true;					this.$set(this.disabled, 1, true);					this.$set(this.disabled, 2, false);					this.$set(this.disabled, 3, false);					this.onBluetoothDeviceFound();				},				fail: e => {					console.log('搜索蓝牙设备失败,错误码:' + e.errCode);					if (e.errCode !== 0) {						initTypes(e.errCode);					}				}			});		},		/**		 * 停止搜索蓝牙设备		 */		stopBluetoothDevicesDiscovery(types) {			uni.stopBluetoothDevicesDiscovery({				success: e => {					console.log('停止搜索蓝牙设备:' + e.errMsg);					if (types) {						this.$set(this.disabled, 1, true);					} else {						this.$set(this.disabled, 1, false);					}					this.$set(this.disabled, 2, true);					// this.$set(this.disabled, 3, true);					this.searchLoad = false;				},				fail: e => {					console.log('停止搜索蓝牙设备失败,错误码:' + e.errCode);					if (e.errCode !== 0) {						initTypes(e.errCode);					}				}			});		},		/**		 * 发现外围设备		 */		onBluetoothDeviceFound() {			uni.onBluetoothDeviceFound(devices => {				console.log('开始监听寻找到新设备的事件');				// this.$set(this.disabled, 3, false);				this.getBluetoothDevices();			});		},		/**		 * 获取在蓝牙模块生效期间所有已发现的蓝牙设备。包括已经和本机处于连接状态的设备。		 */		getBluetoothDevices() {			uni.getBluetoothDevices({				success: res => {					this.newDeviceLoad = false;					console.log('获取蓝牙设备成功:' + res.errMsg);					// console.log(JSON.stringify(res))					this.list = res.devices;				},				fail: e => {					console.log('获取蓝牙设备错误,错误码:' + e.errCode);					if (e.errCode !== 0) {						initTypes(e.errCode);					}				}			});		},		/**		 * 获取本机蓝牙适配器状态		 */		getBluetoothAdapterState() {			console.log('--->');			uni.getBluetoothAdapterState({				success: res => {					console.log(JSON.stringify(res));					this.adapterState = res;				},				fail: e => {					console.log('获取本机蓝牙适配器状态失败,错误码:' + e.errCode);					if (e.errCode !== 0) {						initTypes(e.errCode);					}				}			});		},		/**		 * 连接低功耗蓝牙		 */		createBLEConnection() {			let deviceId = this.equipment[0].deviceId;			uni.showToast({				title: '连接蓝牙...',				icon: 'loading',				duration: 99999			});			uni.createBLEConnection({				// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接				deviceId,				success: res => {					console.log(res);					console.log('连接蓝牙成功:' + res.errMsg);					// 连接设备后断开搜索 并且不能搜索设备					this.stopBluetoothDevicesDiscovery(true);					uni.hideToast();					uni.showToast({						title: '连接成功',						icon: 'success',						duration: 2000					});					this.$set(this.disabled, 3, true);					this.$set(this.disabled, 4, true);					this.$set(this.disabled, 5, false);					this.$set(this.disabled, 9, false);					this.connected = true;				},				fail: e => {					console.log('连接低功耗蓝牙失败,错误码:' + e.errCode);					if (e.errCode !== 0) {						initTypes(e.errCode);					}				}			});		},		/**		 * 断开与低功耗蓝牙设备的连接		 */		closeBLEConnection() {			let deviceId = this.equipment[0].deviceId;			uni.closeBLEConnection({				deviceId,				success: res => {					console.log(res);					console.log('断开低功耗蓝牙成功:' + res.errMsg);					this.$set(this.disabled, 1, false);					this.$set(this.disabled, 3, true);					this.$set(this.disabled, 4, true);					this.$set(this.disabled, 5, true);					this.$set(this.disabled, 6, true);					this.$set(this.disabled, 7, true);					this.$set(this.disabled, 8, true);					this.$set(this.disabled, 9, true);					this.equipment = [];					this.servicesData = [];					this.characteristicsData = [];				},				fail: e => {					console.log('断开低功耗蓝牙成功,错误码:' + e.errCode);					if (e.errCode !== 0) {						initTypes(e.errCode);					}				}			});		},		/**		 * 获取所有服务		 */		getBLEDeviceServices() {			let deviceId = this.equipment[0].deviceId;			console.log('获取所有服务的 uuid:' + deviceId);			uni.getBLEDeviceServices({				// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接				deviceId,				success: res => {					console.log(JSON.stringify(res.services));					console.log('获取设备服务成功:' + res.errMsg);					this.$set(this.disabled, 7, true);					this.$set(this.disabled, 8, true);					this.showMaskType = 'service';					this.list = res.services;					this.characteristicsData = [];					if (this.list.length <= 0) {						toast('获取服务失败,请重试!');						return;					}					this.maskShow = true;				},				fail: e => {					console.log('获取设备服务失败,错误码:' + e.errCode);					if (e.errCode !== 0) {						initTypes(e.errCode);					}				}			});		},		/**		 * 获取某个服务下的所有特征值		 */		getBLEDeviceCharacteristics() {			let deviceId = this.equipment[0].deviceId;			let serviceId = this.servicesData[0].uuid;			console.log(deviceId);			console.log(serviceId);			uni.getBLEDeviceCharacteristics({				// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接				deviceId,				// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取				serviceId,				success: res => {					console.log(JSON.stringify(res));					console.log('获取特征值成功:' + res.errMsg);					this.$set(this.disabled, 7, true);					this.valueChangeData = {};					this.showMaskType = 'characteristics';					this.list = res.characteristics;					if (this.list.length <= 0) {						toast('获取特征值失败,请重试!');						return;					}					this.maskShow = true;				},				fail: e => {					console.log('获取特征值失败,错误码:' + e.errCode);					if (e.errCode !== 0) {						initTypes(e.errCode);					}				}			});		},		/**		 * 监听低功耗蓝牙连接状态的改变事件。包括开发者主动连接或断开连接,设备丢失,连接异常断开等等		 */		onBLEConnectionStateChange() {			uni.onBLEConnectionStateChange(res => {				// 该方法回调中可以用于处理连接意外断开等异常情况				console.log(`蓝牙连接状态 -------------------------->`);				console.log(JSON.stringify(res));				if (!res.connected) {					if(this.isStop) return ;					console.log('断开低功耗蓝牙成功:');					this.$set(this.disabled, 1, false);					this.$set(this.disabled, 3, true);					this.$set(this.disabled, 4, true);					this.$set(this.disabled, 5, true);					this.$set(this.disabled, 6, true);					this.$set(this.disabled, 7, true);					this.$set(this.disabled, 8, true);					this.$set(this.disabled, 9, true);					this.searchLoad = false;					this.equipment = [];					this.servicesData = [];					this.characteristicsData = [];					this.valueChangeData = {};					toast('已经断开当前蓝牙连接');				}			});		},		/**		 * 读取低功耗蓝牙设备的特征值的二进制数据值。注意:必须设备的特征值支持 read 才可以成功调用		 */		readBLECharacteristicValue() {			let deviceId = this.equipment[0].deviceId;			let serviceId = this.servicesData[0].uuid;			let characteristicId = this.characteristicsData[0].uuid;			console.log(deviceId);			console.log(serviceId);			console.log(characteristicId);			uni.readBLECharacteristicValue({				// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接				deviceId,				// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取				serviceId,				// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取				characteristicId,				success: res => {					console.log('读取设备数据值成功');					console.log(JSON.stringify(res));					this.notifyBLECharacteristicValueChange();				},				fail(e) {					console.log('读取设备数据值失败,错误码:' + e.errCode);					if (e.errCode !== 0) {						initTypes(e.errCode);					}				}			});			this.onBLECharacteristicValueChange();		},		/**		 * 监听低功耗蓝牙设备的特征值变化事件。必须先启用 notifyBLECharacteristicValueChange 接口才能接收到设备推送的 notification。		 */		onBLECharacteristicValueChange() {			// 必须在这里的回调才能获取			uni.onBLECharacteristicValueChange(characteristic => {				console.log('监听低功耗蓝牙设备的特征值变化事件成功');				console.log(JSON.stringify(characteristic));				this.valueChangeData = characteristic;			});		},		/**		 * 订阅操作成功后需要设备主动更新特征值的 value,才会触发 uni.onBLECharacteristicValueChange 回调。		 */		notifyBLECharacteristicValueChange() {			let deviceId = this.equipment[0].deviceId;			let serviceId = this.servicesData[0].uuid;			let characteristicId = this.characteristicsData[0].uuid;			let notify = this.characteristicsData[0].properties.notify;			console.log(deviceId);			console.log(serviceId);			console.log(characteristicId);			console.log(notify);			uni.notifyBLECharacteristicValueChange({				state: true, // 启用 notify 功能				// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接				deviceId,				// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取				serviceId,				// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取				characteristicId,				success(res) {					console.log('notifyBLECharacteristicValueChange success:' + res.errMsg);					console.log(JSON.stringify(res));				}			});		},		/**		 * 	断开蓝牙模块		 */		closeBluetoothAdapter(OBJECT) {			uni.closeBluetoothAdapter({				success: res => {					console.log('断开蓝牙模块成功');					this.isStop = true ;					this.$set(this.disabled, 0, false);					this.$set(this.disabled, 1, true);					this.$set(this.disabled, 2, true);					this.$set(this.disabled, 3, true);					this.$set(this.disabled, 4, true);					this.$set(this.disabled, 5, true);					this.$set(this.disabled, 6, true);					this.$set(this.disabled, 7, true);					this.$set(this.disabled, 8, true);					this.$set(this.disabled, 9, true);					this.$set(this.disabled, 10, true);					this.equipment = [];					this.servicesData = [];					this.characteristicsData = [];					this.valueChangeData = {};					this.adapterState = [];					this.searchLoad =false;					toast('断开蓝牙模块');				}			});		}	}};/** * 判断初始化蓝牙状态 */function initTypes(code, errMsg) {	switch (code) {		case 10000:			toast('未初始化蓝牙适配器');			break;		case 10001:			toast('未检测到蓝牙,请打开蓝牙重试!');			break;		case 10002:			toast('没有找到指定设备');			break;		case 10003:			toast('连接失败');			break;		case 10004:			toast('没有找到指定服务');			break;		case 10005:			toast('没有找到指定特征值');			break;		case 10006:			toast('当前连接已断开');			break;		case 10007:			toast('当前特征值不支持此操作');			break;		case 10008:			toast('其余所有系统上报的异常');			break;		case 10009:			toast('Android 系统特有,系统版本低于 4.3 不支持 BLE');			break;		default:			toast(errMsg);	}}/** * 弹出框封装 */function toast(content, showCancel = false) {	uni.showModal({		title: '提示',		content,		showCancel	});}</script><style>.uni-title {	/* width: 100%; */	/* height: 80rpx; */	text-align: center;}.uni-mask {	position: fixed;	top: 0;	left: 0;	bottom: 0;	display: flex;	align-items: center;	width: 100%;	background: rgba(0, 0, 0, 0.6);	padding: 0 30rpx;	box-sizing: border-box;}.uni-scroll_box {	height: 70%;	background: #fff;	border-radius: 20rpx;}.uni-list-box {	margin: 0 20rpx;	padding: 15rpx 0;	border-bottom: 1px #f5f5f5 solid;	box-sizing: border-box;}.uni-list:last-child {	border: none;}.uni-list_name {	font-size: 30rpx;	color: #333;}.uni-list_item {	font-size: 24rpx;	color: #555;	line-height: 1.5;}.uni-success_box {	position: absolute;	left: 0;	bottom: 0;	min-height: 100rpx;	width: 100%;	background: #fff;	box-sizing: border-box;	border-top: 1px #eee solid;}.uni-success_sub {	/* width: 100%%; */	height: 100rpx;	display: flex;	justify-content: space-between;	align-items: center;	padding: 0 30rpx;}.uni-close_button {	padding: 0 20rpx;	height: 60rpx;	line-height: 60rpx;	background: #ce3c39;	color: #ffffff;	border-radius: 10rpx;}.uni-success_content {	height: 600rpx;	margin: 30rpx;	margin-top: 0;	border: 1px #eee solid;	padding: 30rpx;}.uni-content_list {	padding-bottom: 10rpx;	border-bottom: 1px #f5f5f5 solid;}.uni-tips {	text-align: center;	font-size: 24rpx;	color: #666;}</style>
 |