<template>
	<!-- 自定义导航栏 -->
    <view class="bluetooth">
	   <view class="navBarBox">
			<!-- 状态栏占位 -->
			<view class="statusBar" :style="{ paddingTop: statusBarHeight + 'px' }"></view>
			<!-- 真正的导航栏内容 -->
			<view class="navBar">
				<view class="titlefont" style="margin-left: 10px;">通信设备</view>
			</view>
		</view>
        <!-- 发送数据 -->
      <view class="send">
            <view class="uni-textarea">
                <view @tap="send_data" class="fasong">发送</view>
				<view class="">
					蓝牙返回的数据为:
				</view>
            </view>

        </view>
        <!-- 没有匹配的蓝牙设备 -->
		
       <view class="no_match_bluetooth_list" v-if="no_match_list.length!=0">
            <view class="h1">附近蓝牙设备</view>
			<scroll-view scroll-y="100%">
            <flex  v-for="(item,index) in no_match_list" :key="index" >
                <view class="uni-list" @tap="print(item.SN)">
                    <view class="uni-list-cell" hover-class="uni-list-cell-hover">
                        <view class="uni-list-cell-navigate uni-navigate-right uni-media-list ">
                            <view class="uni-media-list-body">
								<image src="@/static/img/lanya.png" class="lanyaimg" mode="scaleToFill"></image>
								<view class="lanySn"> {{item.name}} </view>
                            </view>
                        </view>
                    </view>
                </view>
            </flex>
			</scroll-view>
        </view>

        <view>
			<popuphelp :helpshowModal="helpshowPay" @helpclose="oncloseahelp"></popuphelp>
		</view>
        <view class="btn">
            <view class="btn_1" @tap="open_bluetooth()">帮 助</view>
            <view class="btn_3" @tap="search_bluetooth()">刷 新</view>
        </view>
    </view>
</template>

<script>
	import popuphelp from "@/pages/main/popuphelp.vue"
	import blueTool from '../../common/dataFormatUtil.js';
	import uTool from '../../common/buletoothUtil.js'
    var main, Context, BluetoothManager, BluetoothAdapter, BManager, BAdapter,BluetoothDevice,IntentFilter,bluetoothSocket,device,_self;
	export default {
		components:{
			popuphelp
		},
        data() {
            return {
                bArray:[],//用于搜索蓝牙去重用的
                no_match_list:[],//没有配对的蓝牙列表
                send_data_onoff:false,
                send_data_list:'',//要发送的数据
				statusBarHeight: 0,// 状态栏高度
				helpshowPay: false,
				show: false,
				timer: null,
				BDeviceList:[],
				fa: '',
				shou: '',
				serviceId: '', //蓝牙服务 uuid
				connectionid: '', //设备的 id
				characteristicid: '', //特征
				sheb: "",
				mList:[],//搜索到的设备列表
				mDeviceId:0,//连接的设备
				targetNumber:'',//要连接的指定设备
            };
        },
        onLoad() {
			//获取手机状态栏高度
			this.statusBarHeight = uni.getSystemInfoSync()['statusBarHeight'];
            //获取android应用Activity对象
            main = plus.android.runtimeMainActivity();
            Context = plus.android.importClass("android.content.Context");
            BManager = main.getSystemService(Context.BLUETOOTH_SERVICE);
            //蓝牙适配器
            BluetoothAdapter = plus.android.importClass("android.bluetooth.BluetoothAdapter");
            //蓝牙本地适配器
            BAdapter = BluetoothAdapter.getDefaultAdapter();
            //蓝牙设备
            BluetoothDevice = plus.android.importClass('android.bluetooth.BluetoothDevice');
            //过滤器
            IntentFilter = plus.android.importClass('android.content.IntentFilter');
			//判断蓝牙是否开启
			if (!BAdapter.isEnabled()) {
				BAdapter.enable();//启动蓝牙
				//在页面加载时候初始化蓝牙适配器
				uni.openBluetoothAdapter({
				    success: e => { 
				        this.$data.isOpenBle = true;
				    },
				    fail: e => {
				        console.log('初始化蓝牙失败,错误码:' + (e.errCode || e.errMsg));
				    }
				});
			}
			self = this;
			self.search_bluetooth()
        },
		mounted(){
			//监听本机蓝牙状态
			uni.onBluetoothAdapterStateChange(function(res) {
				// console.log('adapterState changed, now is', res)
			})
			//监听搜索设备
			uni.onBluetoothDeviceFound(devices => {
				let arr={
					"name": devices.devices[0].name,
					"SN": devices.devices[0].deviceId
				}
				var name=arr.name+arr.SN;
				if(arr.name!=""&&arr.name!=null&&arr.name!=undefined){
					if(this.bArray.indexOf(name) == -1){ //去重
						this.bArray.push(name)
						this.no_match_list.push(arr)
						this.mList.push(devices.devices[0])
					}
				}
			})
			this.onBLEConnectionStateChange()
			this.onBLECharacteristicValueChange()
		},
        methods:{
			open_bluetooth(){
				this.oncloseahelp()
				this.helpshowPay = true //传给子组件动态控制显示隐藏
			},
			oncloseahelp(show){
				this.helpshowPay = show;
			},
			onBLECharacteristicValueChange() {
				uni.onBLECharacteristicValueChange(function(res) {
					console.log(`监听低功耗蓝牙设备的特征值变化事件 ${res.characteristicId} has changed, now is ${res.value}`)
				})
			},
			
			onBLEConnectionStateChange() {
				uni.onBLEConnectionStateChange(res => {
					// 该方法回调中可以用于处理连接意外断开等异常情况
					if (res.connected == false) {
						console.log(`device ${res.deviceId} state has changed, connected: ${res.connected}`)
					}
				})
			},
			
			//搜索蓝牙设备
			search_bluetooth(){
				//判断蓝牙是否开启
				if (!BAdapter.isEnabled()) {
					BAdapter.enable();//启动蓝牙
				}
				/* 1、初始化蓝牙 uni.openBluetoothAdapter(OBJECT) */
				uni.openBluetoothAdapter({
				    success: e => { 						
						/* 初始化蓝牙成功 */
						/* 2、开始搜索蓝牙设备 uni.startBluetoothDevicesDiscovery(OBJECT */
						uni.startBluetoothDevicesDiscovery({
							allowDuplicatesKey:false,//是否允许同一设备多次上报,但RSSI值会有所不同
							success: (res) => {
								console.log("搜索成功")
							},
							fail: (res) => {
								console.log("搜索失败")
							}						
						})
				        this.$data.isOpenBle = true;
				    },
				    fail: e => {
				        console.log('初始化蓝牙失败,错误码:' + (e.errCode || e.errMsg));
				    }
				});
				setTimeout(() => {
					uni.startBluetoothDevicesDiscovery({
						// services: ['FEE7'],
						// allowDuplicatesKey:true,
						success: resd => {
							//to do
						},
						fail: errd => {
							//to do
						}
					})
				}, 1000)
			},
			
            /**
            * 根据蓝牙地址,连接设备
            * @param {Object} address
            * @return {Boolean}
            */
            print(deviceId){
			    uni.showModal({
				    title: '提示',
				    content: '是否连接此蓝牙?',
				    success: function (res) {
						//1.创建蓝牙连接
						uni.createBLEConnection({
							deviceId: deviceId,
							timeout:5000,
							success: res => {
								uni.showLoading({
								    title: '蓝牙连接中...'
								});
								self.mDeviceId = deviceId;
								self.getBLEDeviceServices(deviceId)
								//2.创建蓝牙连接成功后关闭蓝牙搜索
								uni.stopBluetoothDevicesDiscovery({
									success(resds) {
										// 打开输入发送数据
										this.send_data_onoff=true;  
									}
								})
					
							},
							fail: err => {
								console.log("连接失败")
								console.log(error);
							}
						})
				    }
			    });
				
            },
			/* 获取所有的服务(目前理解来说应该是进入服务) */
			getBLEDeviceServices(deviceId){
				setTimeout(()=>{
					uni.getBLEDeviceServices({
						// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
						deviceId,
						success: (res) => {																						
							res.services.forEach((item)=>{
								let serviceId = item.uuid;
								if(serviceId.includes("0000FFE0")&&item.isPrimary){
									console.log('serverId:',serviceId)
									/* 进入特征值 */
									self.getBLEDeviceCharacteristics(deviceId,serviceId);
								}
							})
						},
					   fail(res) {
						   console.log("获取服务失败")
						   console.log(error)
					   }
					})
				},1000)
			},
			/* 进入特征值 */
			getBLEDeviceCharacteristics(deviceId,serviceId){
				var flag = true;
				setTimeout(()=>{
					uni.getBLEDeviceCharacteristics({
						// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
						deviceId,
						// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
						serviceId,
						success: res1 => {	
							res1.characteristics.forEach((item)=>{
								let characteristicId = item.uuid;
								if (item.properties.write&&item.properties.notify&&flag) {
									self.mDeviceId = deviceId
									self.serviceId = serviceId
									self.characteristicId = characteristicId
									self.notifyBLECharacteristicValueChange(deviceId,serviceId,characteristicId)
									flag = false;
								}
							})															
						},
					    fail: (error) => {
						  console.log("获取服务失败")
						  console.log(error)
					    }
					})
				},1000)
			},
			notifyBLECharacteristicValueChange(deviceId,serviceId,characteristicId){
				uni.notifyBLECharacteristicValueChange({
				    state: true, // 启用 notify 功能
				     // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
				    deviceId,
				    // 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
				    serviceId,
				    // 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
				    characteristicId,
				    success:(res)=> {
					    /* 连接成功 */
						uni.hideLoading();
					    uni.showToast({
							duration:3000,
							title:"连接成功",
							icon:'success'
					    });
						// uni.navigateTo({
						//     url: '/pages/home/home'
						// })
				    },
				    fail:(res)=> {
					    uni.hideLoading();
					    console.log('notifyBLECharacteristicValueChange success', res.errMsg)
				    }
				})
			},						
            /* 连接成功以后,执行设置的操作,并且打开返回值的监听开关并监听 */
			send_data() {
				/* 获取所有的服务 */
				/* 每次设置钱都将notify打开(设备回复开关) */
				// let tokenArr = '01030080000C4427';	
				let tokenArr = '0103011000404403';
				let arrayBuffer = blueTool.string2buffer(tokenArr)
				/* 测试发现如果不做分包发送的话,还是会有问题,所以这边还是需要做分包发送 */
				self.writeDevice(arrayBuffer);
				/* 这边对特征值2进行数据的监听  */
				let resultAll="";
				uni.onBLECharacteristicValueChange(function(CALLBACK){
					let result = blueTool.ab2hex(CALLBACK.value);
					resultAll += result;
					console.log("接收报文:",resultAll)
				
				})
				
			},
			/* 执行演示分包操作 */
			writeDevice(_Buffer){
				let Num = 0;
				let ByteLength = _Buffer.byteLength;
				let i = 1;
				while (ByteLength > 0) {
					i++;
					let TmpBuffer;
					if(ByteLength > 20){
						TmpBuffer = _Buffer.slice(Num, Num + 20);
						Num += 20;
						ByteLength -= 20;
						console.log('执行常规循环')
						uTool.delayed(500).then(()=>{
							uni.writeBLECharacteristicValue({
                                deviceId:self.mDeviceId,
                                serviceId:self.serviceId,
                                characteristicId:self.characteristicId,
                                value: TmpBuffer,
                                success: (res) => {
                                    /* 发送成功 */
                                    console.log('前面的循环成功', res)
                                },
                                fail: (error) => {
                                    /* 发送失败 */
                                    console.log('前面的循环失败',error)
                                } 
                             })
						})
					}else{
						console.log('执行最后一次')
						TmpBuffer = _Buffer.slice(Num, Num + ByteLength)
						Num += ByteLength
						ByteLength -= ByteLength
						/* 当长度不满20的时候执行最后一次发送即可 */
						uni.writeBLECharacteristicValue({
							deviceId:self.mDeviceId,
							serviceId:self.serviceId,
							characteristicId:self.characteristicId,
							value: TmpBuffer,
							success: (res) => {
								/* 发送成功 */
								console.log('最后一次写入成功', res)
							},
							fail: (error) => {
								/* 发送失败 */
								console.log('最后一次写入失败',error)
							}
					  })
					}
				}
			}
        }
    }
</script>

<style lang="scss">
	.lanySn{
		margin-left: 20rpx;
	}
	.uni-media-list-body{
		margin-top: 10rpx;
		margin-left: 15rpx;
		display: flex;
	}
	.lanyaimg{
		width: 50rpx;
		height: 50rpx;
	}
	.bluetooth{
		.navBarBox .navBar {
			display: flex;
			flex-direction: row;
			justify-content: flex-start;
			align-items: center;
			background: #333878;
			height: 92rpx;
			line-height: 80rpx;
			font-size: 36rpx;
			color: #FFFFFF;
		}
		.h1{
			padding: 20upx 0;color: #1482D1;border-top: 1upx solid #EFEFF4;
		}
		
		.btn{
			display:flex;position:fixed;
			bottom:0upx;
			justify-content:space-around;
			width: 100%;
			color:#fff;
			background-color: #fff;
			view{
				width: 49%;
				height: 110upx;
				line-height:110upx;
				text-align: center;			
			}
			.btn_1{
				font-size: 36rpx;
				background-color: #4768A9;
			}
			.btn_3{
				font-size: 36rpx;
				background-color: #02238E;
			}
		}
		.uni-textarea{
			textarea{
				border: 1px solid #EFEFF4;border-radius: 10px;width: 100%;padding: 10upx;box-sizing: border-box;
			}
			.fasong{
				width: 100%;padding:15upx 10upx;box-sizing: border-box;border-radius: 10px;background: #1482D1;text-align: center;color: white;margin: 10px 0;
			}
		}
	}
</style>

蓝牙通信工具 buletoothUtil.js

export default{
	/* 蓝牙通信工具 */
	getError(errorCode){
		if(errorCode == 0) return "OK";
		if(errorCode == 10000) return "未初始化蓝牙适配器";
		if(errorCode == 10001) return "当前蓝牙适配器不可用";
		if(errorCode == 10002) return "没有找到指定设备";
		if(errorCode == 10003) return "连接失败";
		if(errorCode == 10004) return "没有找到指定服务";
		if(errorCode == 10005) return "没有找到指定特征值";
		if(errorCode == 10006) return "当前连接已断开";
		if(errorCode == 10007) return "当前特征值不支持此操作";
		if(errorCode == 10008) return "其余所有系统上报的异常";
		if(errorCode == 10009) return "Android 系统特有,系统版本低于 4.3 不支持 BLE";
		return "未知异常";
	},
	/* 异步执行,延时函数 */
	delayed(ms,res){
		return new Promise((resolve,reject) =>{
			setTimeout(function(){
				resolve(res);
			},ms)
		});
	}
}

数据格式的转换工具类dataFormatUtil.js

/* 数据格式的转换工具类 */
export default{
	/* 字符串转arraybuffer */
	string2buffer: function(str) {
		// 首先将字符串转为16进制
		let val = str
		// 将16进制转化为ArrayBuffer
		return new Uint8Array(val.match(/[\da-f]{2}/gi).map(function(h) {
			return parseInt(h, 16)
		})).buffer
	},
	ab2hex(buffer) {
		const hexArr = Array.prototype.map.call(
			new Uint8Array(buffer),
				function(bit) {
				return ('00' + bit.toString(16)).slice(-2)
			}
		)
		return hexArr.join('')
	},
	/* arraybuffer 转字符串 */
	bufferString: function(str) {
		// 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('')
		}
		//16进制
		let systemStr = ab2hex(str)
		// console.log(hexCharCodeToStr(systemStr),99)
		function hexCharCodeToStr(hexCharCodeStr) {
			var trimedStr = hexCharCodeStr.trim();
			var rawStr = trimedStr.substr(0, 2).toLowerCase() === "0x" ?trimedStr.substr(2):trimedStr;
			var len = rawStr.length;
			if (len % 2 !== 0) {
				alert("Illegal Format ASCII Code!");
				return "";
			}
			var curCharCode;
			var resultStr = [];
			for (var i = 0; i < len; i = i + 2) {
				curCharCode = parseInt(rawStr.substr(i, 2), 16); // ASCII Code Value
				let str5 = String.fromCharCode(curCharCode)
				if (str5.startsWith('\n') == false) {
					resultStr.push(String.fromCharCode(curCharCode));
				}
			}
			return resultStr.join("");
		
		}
		// console.log(hexCharCodeToStr(systemStr),888)
		return hexCharCodeToStr(systemStr)
	
	},
	
}

弹出框:蓝牙设置页面 popuphelp.vue

<template>
	<view class="payment">
		<u-popup v-model="show" mode="center" :show='show' :mask-close-able='false'>
			<view class="popup-project">
				<view class="massage">
					<view class="left">
						<image src="@/static/img/tixing.png" class="tixingimg"></image>
					</view>
					<view class="right">
	
					</view>
				</view>
				<view class="buttonBox">		
					<button class="btn1" plain="true" @tap="okPopup">设置蓝牙</button>
					<button class="btn2" plain="true" @tap="cancelPopup">关闭</button>
				</view>
			</view>
		</u-popup>
	</view>
</template>

<script>
	export default {
		name: "alzPopup",
		data(){
			return{
				show: false, //弹出框显示状态
			}
		},
		props: {
			helpshowModal: {
				type: Boolean,
				default: ''
			}
		},
		watch: {
			helpshowModal(val) {
				this.show = val;
			}
		},
		onLoad(){},
		methods:{
			//取消
			cancelPopup() {
				this.show = false
				this.$emit('helpclose', this.show)
			},
			//蓝牙设置
			okPopup() {
				var main = plus.android.runtimeMainActivity();  
				var Intent = plus.android.importClass("android.content.Intent");  
				var mIntent = new Intent('android.settings.BLUETOOTH_SETTINGS');  
				main.startActivity(mIntent);  
			},
		}
	}
</script>

<style lang="scss" scoped>

	.popup-project {
		background: #fff;
		width: 600rpx;
		position: relative;
		box-shadow: 0 0 20rpx #5d5d5d;
		.massage{
			display:flex;
			width: 100%;
			height: 900rpx;
			.left{
				width: 15%;
				background: #01ABF1;
				text-align: center;
				.tixingimg{
					width: 50rpx;
					height: 50rpx;
					margin-top: 20rpx;
				}
			}
			.right{
				width: 85%;
				.fonth4{
					font-size: 42rpx;
					margin-top: 28rpx;
					margin-left: 20rpx;
				}
				.p1{
					margin-top: 30rpx;
					margin-left: 20rpx;
				}
			}
		}
		.buttonBox {
			display:flex;
			bottom:0upx;
			justify-content:space-around;
			width: 100%;
			color:#fff;
			background-color: #fff;
			border-radius:0px;
			.btn1 {
				width: 49.7%;
				color: #FFFFFF;
				background: #5169a9;
				height: 110upx;
				line-height:110upx;
				text-align: center;	
				border-radius:0rpx;
				margin-left: 0rpx;
				
			}
			.btn2 {
				width: 49.7%;
				color: #FFFFFF;
				background: #0b2385;
				height: 110upx;
				line-height:110upx;
				text-align: center;	
				border-radius:0px;
				margin-right:0rpx;
			}
		}
	}
	
</style>

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐