uni-app实现跨端开发手机蓝牙接收和发送数据

最近接触uni-app夸终端开发手机蓝牙模块的接收和发送数据功能,

手机蓝牙模块接发收数据主要流程步骤如下:

1、初始化手机蓝牙

2、根据设备id获取蓝牙服务,

3、根据蓝牙服务获取对应的蓝牙特征值

4、监听蓝牙特征值数值变化,发送对应数据到蓝牙特征值

具体

<template>
  <view class="form-box_wrapper">
    <u-toast ref="uToast"></u-toast>
		<view class="item-box" v-for="(v, idx) in bluesList" :key="idx" @click="getBlueServe(v.deviceId)" v-show="v.name">
			<image src='/static/blue.jpeg' class="icon"/>
			<text class="name">{{v.name || '--'}}</text>
			<image src='/static/s5.png' class="rssi" v-if="v.RSSI >= -41"/>
			<image src='/static/s4.png' class="rssi" v-else-if="v.RSSI >= -55"/>
			<image src='/static/s3.png' class="rssi" v-else-if="v.RSSI >= -65"/>
			<image src='/static/s2.png' class="rssi" v-else-if="v.RSSI >= -75"/>
			<image src='/static/s1.png' class="rssi" v-if="v.RSSI < -75"/>
		</view>
		<view style="padding-top: 100rpx;" v-if="!bluesList.length">
			<u-empty mode="data"></u-empty>
		</view>
  </view>
</template>

<script>
import { objArraySort } from '../../utils/index.js';
import { houseTypes, addressList, mountTypes, blueIntCode } from './enmu.js';
export default {
  data () {
    return {
			id:0, // 使用 marker点击事件 需要填写id
			title: 'map',
      value: 50,
      bluesList: [], // 蓝牙列表
    };
  },
	onHide () {
		console.log('onUnload');
	},
	onUnload () {
		this.stop();
		console.log('onUnload');
	},
	onPullDownRefresh () {
		this.stop();
		this.submit();
		setTimeout(function () {
			uni.stopPullDownRefresh();
		}, 1000);
	},
  onReady () {
    // 蓝牙适配器变化
    uni.onBluetoothAdapterStateChange(function (res) {
      console.log(res);
    });
		this.submit();
  },
  methods: {
		// 跳转蓝牙设置
		openSystemBluetoothSetting () {
			wx.openSystemBluetoothSetting({
			  success (res) {
			    console.log(res)
			  }
			});
		},
		// 播放背景音乐
		playAd () {
			this.bgAudioManager.play(); // 暂停音乐播放
		},
		// 暂停背景音乐播放
		stopPlay () {
			this.bgAudioManager.stop(); // 暂停音乐播放
		},
		// 播放背景音乐
		getBackgroundAudioManager () {
			// #ifdef APP-PLUS
			this.bgAudioManager = uni.getBackgroundAudioManager();
			this.bgAudioManager.title = '致爱丽丝';
			this.bgAudioManager.singer = '暂无';
			this.bgAudioManager.coverImgUrl = 'https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-uni-app-doc/7fbf26a0-4f4a-11eb-b680-7980c8a877b8.png';
			this.bgAudioManager.src = 'https://bjetxgzv.cdn.bspapp.com/VKCEYUGU-hello-uniapp/2cc220e0-c27a-11ea-9dfb-6da8e309e0d8.mp3';
			// #endif
		},
    getBLEDeviceRSSI (deviceId) {
      const vm = this;
      uni.getBLEDeviceCharacteristics({
        // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
        deviceId,
        success (res) {
          vm.$refs.uToast.show({
            position: 'center',
            type: 'success',
            message: '获取蓝牙信号强度成功'
          });
          console.log('获取蓝牙信号强度成功', res);
        },
        fail (res) {
          vm.$refs.uToast.show({
            position: 'center',
            type: 'error',
            message: res.errMsg
          });
        }
      });
    },
    getBlueServe (deviceId) {
			console.log(deviceId, 'deviceId');
      uni.navigateTo({
        url: `/pages/gird/index?deviceId=${deviceId}`
      });
			// this.createBLEConnection(deviceId);
    },
    stop () {
      uni.stopBluetoothDevicesDiscovery({
        success (res) {
          uni.showToast({
            title: '停止搜索蓝牙成功',
            duration: 2000
          });
        }
      });
			uni.closeBluetoothAdapter({
			  success () {
			    uni.showToast({
			      title: '关闭蓝牙链接成功',
			      duration: 2000
			    });
			  }
			});
    },
    submit () {
      const vm = this;
      uni.openBluetoothAdapter({
        success (res) {
          console.log(res, '-=-=-');
          if (res.errMsg == 'openBluetoothAdapter:ok') {
            uni.showToast({
              title: '初始化蓝牙成功',
              duration: 2000
            });
            // 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('')
            }

            // 搜索蓝牙设备
            uni.startBluetoothDevicesDiscovery({
              success (res) {
                console.log(res, '------蓝牙设备列表-----');
                uni.showToast({
                  title: '正在查找蓝牙设备',
                  duration: 2000
                });
                vm.bluesList = res.devices || [];
              }
            });

            // 查看蓝牙设备列表
            uni.onBluetoothDeviceFound(function (devices) {
              console.log('====找到新的蓝牙设备====');
              devices.devices.forEach(v => {
                const blues = vm.bluesList.find(val => (v.deviceId == val.deviceId || v.name == val.name));
                if (!blues) {
                  vm.bluesList.push(v);
                  vm.bluesList = objArraySort(vm.bluesList, 'RSSI', 'des'); // 根据信号点强弱排序
                }
              });
            });
          } else {
            // uni.showToast({
            // 	title: blueIntCode[res.errno],
            // 	duration: 2000
            // });
          }
        },
        fail () {
          uni.showToast({
            title: '蓝牙初始化失败,请检查手机蓝牙是否开启',
            duration: 2000
          });
        }
      });
    },
    showHouseType (val) {
      this[`show${val}`] = true;
    },
    confirm (val, key) {
      // 时间类型
      if (val.timestamp) {
        this.form[key] = `${val.year}-${val.month}-${val.day}`;
      } else {
        this.form[key] = val[0].label;
      }
    }
  }
};
</script>
	
<style lang="scss" scoped>
.form-box_wrapper {
  padding: 0 40rpx 40rpx 40rpx;
	::v-deep.u-button {
		margin: 10rpx 0;
	}
	.item-box {
		display: flex;
		height: 100rpx;
		padding: 10rpx;
		line-height: 100rpx;
		align-items: center;
		justify-content: space-between;
		border-bottom: 1rpx solid #eee;
		.name {
			overflow: hidden;
			text-overflow:ellipsis;
			white-space: nowrap;
			text-align: left;
			padding: 0 15rpx;
			width: 100%;
		}
		.icon{
			width: 80rpx;
			height: 80rpx;
			border-radius: 50rpx;
		}
		.rssi {
			height: 50rpx;
			width: 70rpx;
		}
	}
  .item {
    border-bottom: 1px dashed #ccc;
  }
}
</style>

<template>
	<view class="content">
		<u-toast ref="uToast"></u-toast>
		<view class="notic-box">
			蓝牙设备id:{{deviceId}}
		</view>
		<u--input
			placeholder="请输入发送值"
			border="surround"
			style="width: 100%;"
			v-model="value"
		></u--input>
		<u-button @click="writeBLECharacteristicValue" type="primary">发送指令</u-button>
		<view>解析值:</view>
		<view class="text">{{msg}}</view>
	</view>
</template>

<script>
	let ecServerIdOption1 = "0000FFF0-0000-1000-8000-00805F9B34FB"; // 服务id
	let ecWriteCharacteristicIdOption1 = "0000FFF2-0000-1000-8000-00805F9B34FB"; // 写特征值id
	let ecReadCharacteristicIdOption1 = "0000FFF1-0000-1000-8000-00805F9B34FB"; // 读特征值id

	// buff 转 str 
	function arrayBufferToString(buffer) {
    let x = new Uint8Array(buffer);
    // log(x)
    let strHex = ""
    let str = ""
    for (let i = 0; i < x.length; i++) {
      strHex = strHex + x[i].toString(16).padStart(2, "0")
      str = str + String.fromCharCode(x[i])
    }
		return strHex;
	}
	// str 转 buff
	function str2ab(str) {
		const buffer = new ArrayBuffer(str.length / 2);
		let x = new Uint8Array(buffer);
		for (let i = 0; i < x.length; i++) {
		    x[i] = parseInt(str.substr(2 * i, 2), 16)
		}
		return buffer;
	}
	export default {
		data() {
			return {
				value: '',
				serviceId: '',
				characteristicId: '',
				services: [], // 服务id
				characteristics: [], // 特征值id
				deviceId: '',
				msg: '',
				title: 'Hello',
			}
		},
		computed: {
			character () {
				const o = this.characteristics.find(v => v.uuid == this.characteristicId);
				return o;
			}
		},
		onUnload () {
			this.closeBLEConnection();
			console.log('onUnload');
		},
		onLoad (option) {
			const vm = this;
			this.deviceId = option.deviceId || '';
			this.createBLEConnection(this.deviceId);
			// 监听特征值
			uni.onBLECharacteristicValueChange(function (characteristic) {
				vm.msg = arrayBufferToString(characteristic.value);
				console.log('buff解析出来的字符串:', vm.msg);
				console.log('characteristic value comed:', characteristic);
			});
		},
		methods: {
			// 读取特征值返回数据
			readBLECharacteristicValue () {
				const vm = this;
				uni.readBLECharacteristicValue({
					// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
					deviceId: vm.deviceId,
					// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
					serviceId: ecServerIdOption1,
					// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
					characteristicId: ecReadCharacteristicIdOption1,
					success(res) {
						console.log('readBLECharacteristicValue:', res);
						// vm.msg = ab2str(res.value);
					},
					fail (res) {
						vm.$refs.uToast.show({
							position: 'center',
							type: 'error',
							message: res.errMsg
						});
					}
				});
			},
			radioChange (serviceId) {
				this.getBLEDeviceCharacteristics(this.deviceId, serviceId);
				console.log(serviceId, 'serviceId');
			},
			openBLEConnection () {
				this.createBLEConnection(this.deviceId);
			},
			// 链接蓝牙服务
			createBLEConnection (deviceId, cb) {
				const vm = this;
				uni.createBLEConnection({
					// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
					deviceId,
					success (res) {
						vm.$refs.uToast.show({
							position: 'center',
							type: 'success',
							message: `${deviceId}-蓝牙建立链接成功`
						});
						vm.getBLEDeviceServices(vm.deviceId);

						// 兼容app端,app端首次加载可能不会获取到对应的服务列表,需要多次刷新请求触发
						vm.severId = setInterval(() => {
							if (vm.services.length) {
								clearInterval(vm.severId);
							}
							vm.getBLEDeviceServices(vm.deviceId);
						}, 3000);

						console.log(res, '连接成功蓝牙');
					},
					fail (res) {
						vm.$refs.uToast.show({
							position: 'center',
							type: 'error',
							message: res.errMsg
						});
					}
				})
			},
			// 关闭蓝牙连接成功
			closeBLEConnection () {
				const deviceId = this.deviceId;
				const vm = this;
				uni.closeBLEConnection({
					deviceId,
					success(res) {
						console.log(res);
						vm.$refs.uToast.show({
							position: 'center',
							type: 'success',
							message: `关闭蓝牙链接成功`
						});
					}
				});
			},
			// 发送对应的指令
			writeBLECharacteristicValue (value = this.value) {

				if (this.value.length % 2 != 0) {
					this.$refs.uToast.show({
						position: 'center',
						type: 'error',
						message: `数据长度只能是双数`
					});
				  return;
				}

				if (!new RegExp("^[0-9a-fA-F]*$").test(this.value)) {
					this.$refs.uToast.show({
						position: 'center',
						type: 'error',
						message: `数据格式错误,只能是0-9,a-f,A-F`
					});
				  return;
				}
				
				const vm = this;
				const buffer = str2ab(this.value);

				console.log('发送的蓝牙特征值:', buffer);

				uni.writeBLECharacteristicValue({
					// 这里的 deviceId 需要在 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
					deviceId: vm.deviceId,
					// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
					serviceId: ecServerIdOption1,
					// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
					characteristicId: ecWriteCharacteristicIdOption1,
					// 这里的value是ArrayBuffer类型
					value: buffer,
					success(res) {
						vm.$refs.uToast.show({
				      position: 'center',
				      type: 'success',
				      message: res.errMsg
				    });
						console.log('writeBLECharacteristicValue success', JSON.stringify(res));
						vm.res = res;
					},
					fail (res) {
				    vm.$refs.uToast.show({
				      position: 'center',
				      type: 'error',
				      message: res.errMsg
				    });
				  }
				});
			},
			// 获取服务对应的特征值
			getBLEDeviceCharacteristics (deviceId = this.deviceId, serviceId = ecServerIdOption1) {
				const vm = this;
				uni.getBLEDeviceCharacteristics({
					deviceId,
					serviceId,
					success(res) {
						console.log('device characteristics:', res.characteristics);
						vm.characteristics = res.characteristics;
						vm.characteristicId = res.characteristics[0].uuid || '';

						// 必须先获取服务,再获取特征值,然后再进行监听。这个步骤必须走完才可以完成监听,不然走不通。后面onBLECharacteristicValueChange
						uni.notifyBLECharacteristicValueChange({
							state: true, // 启用 notify 功能
							// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
							deviceId: vm.deviceId,
							// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
							serviceId: ecServerIdOption1,
							// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
							characteristicId: ecReadCharacteristicIdOption1, // 读服务特征值
							success(res) {
								console.log('notifyBLECharacteristicValueChange连接成功', res);
							}
						});
					}
				});
			},
			getBLEDeviceServices (deviceId) {
				const vm = this;
				uni.getBLEDeviceServices({
				  // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
				  deviceId,
				  success (res) {
				    vm.$refs.uToast.show({
				      position: 'center',
				      type: 'success',
				      message: '获取蓝牙设备服务成功'
				    });
				    console.log('获取蓝牙设备服务成功', JSON.stringify(res));
						
            vm.services = res.services;
						vm.getBLEDeviceCharacteristics(vm.deviceId, ecServerIdOption1);
				  },
				  fail (res) {
				    vm.$refs.uToast.show({
				      position: 'center',
				      type: 'error',
				      message: res.errMsg
				    });
				  }
				});
			},
			// 上传图片
			upload() {
				uni.chooseImage({
					count: 1,
					success(res) {
						console.log(res);
						if (res.tempFilePaths.length > 0) {
							let filePath = res.tempFilePaths[0];
							//进行上传操作

							// promise方式
							uniCloud.uploadFile({
								filePath: filePath, //要上传的文件对象
								cloudPath: Date.now() + '.jpg', //保存在云端的文件名,这里以时间戳命名
								success(res) {
									console.log(res, 'res---');
								}
							});
						}
					}
				});
			}
		}
	}
</script>
<style lang="scss" scoped>
	.notic-box {
		width: 100%;
	}
	.content {
		padding: 5px;
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		::v-deep.u-input {
			width: 95%;
		}
		::v-deep.u-button {
			margin: 10rpx 0;
		}
		.text {
			width: 98%;
			height: 200rpx;
			overflow: auto;
			white-space: pre-wrap;
			word-break: break-all;
		}
	}
</style>

  • 0
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值