当前位置: 首页 > news >正文

微信小程序(uniapp)实现连接蓝牙

微信小程序(uniapp)实现连接蓝牙

一、蓝牙连接的基本流程

在uni-app中实现蓝牙连接,主要包含以下步骤:

  1. 初始化蓝牙模块:开启蓝牙适配器,为后续操作做准备
  2. 搜索蓝牙设备:扫描周围可用的蓝牙设备
  3. 连接目标设备:建立与指定蓝牙设备的连接
  4. 获取服务与特征值:获取设备提供的服务和特征值信息
  5. 数据交互:通过特征值进行数据的读写操作

二、具体实现步骤

1. 初始化蓝牙模块

使用uni.openBluetoothAdapter()方法初始化蓝牙适配器。这是所有蓝牙操作的基础,必须在其他API调用前执行。

// 初始化蓝牙适配器
function initBluetooth() {uni.openBluetoothAdapter({success: (res) => {console.log('蓝牙适配器初始化成功', res);// 初始化成功后可以开始搜索设备searchBluetoothDevices();},fail: (err) => {console.error('蓝牙适配器初始化失败', err);if (err.errCode === 10001) {uni.showModal({title: '提示',content: '请开启手机蓝牙',showCancel: false});}}});
}

2. 搜索蓝牙设备

使用uni.startBluetoothDevicesDiscovery()方法开始搜索附近的蓝牙设备。由于搜索操作会消耗系统资源,建议在连接成功后及时停止搜索。

// 搜索蓝牙设备
function searchBluetoothDevices() {uni.startBluetoothDevicesDiscovery({allowDuplicatesKey: false, // 不允许重复上报同一设备success: (res) => {console.log('开始搜索蓝牙设备', res);uni.showLoading({ title: '正在搜索设备...' });// 设置定时器,15秒后超时停止搜索const timer = setTimeout(() => {stopBluetoothSearch();uni.showModal({title: '提示',content: '搜索设备超时,请检查设备是否开启',showCancel: false});}, 15000);// 监听找到新设备的事件uni.onBluetoothDeviceFound((devices) => {handleFoundDevices(devices);clearTimeout(timer); // 找到设备后清除超时定时器});},fail: (err) => {console.error('开始搜索设备失败', err);uni.hideLoading();}});
}// 处理找到的设备
function handleFoundDevices(devices) {const foundDevices = [];devices.devices.forEach(device => {if (device.name && device.name.includes('目标设备关键字')) {foundDevices.push(device);}});if (foundDevices.length > 0) {stopBluetoothSearch();showDeviceList(foundDevices);}
}// 停止搜索蓝牙设备
function stopBluetoothSearch() {uni.stopBluetoothDevicesDiscovery({success: () => {uni.hideLoading();uni.offBluetoothDeviceFound(); // 停止监听新设备}});
}

3. 显示设备列表并连接

将搜索到的设备显示在页面上,用户可以选择要连接的设备。

// 在Vue组件的data中定义
data() {return {deviceList: [], // 设备列表currentDevice: null // 当前选中的设备}
}// 显示设备列表
function showDeviceList(devices) {this.deviceList = devices;// 可以在这里更新页面显示,或者使用uni-app的列表渲染
}// 连接选中的设备
function connectDevice(deviceId) {uni.createBLEConnection({deviceId: deviceId,success: (res) => {console.log('连接设备成功', res);this.currentDevice = deviceId;// 连接成功后获取设备服务getDeviceServices(deviceId);},fail: (err) => {console.error('连接设备失败', err);uni.showToast({title: '连接失败',icon: 'none'});}});
}

4. 获取设备服务和特征值

连接成功后,需要获取设备提供的服务和特征值,才能进行数据交互。

// 获取设备服务
function getDeviceServices(deviceId) {uni.getBLEDeviceServices({deviceId: deviceId,success: (res) => {console.log('获取服务成功', res.services);// 通常我们只需要特定的服务,可以根据UUID过滤const targetService = res.services.find(service => service.uuid === '目标服务UUID');if (targetService) {getDeviceCharacteristics(deviceId, targetService.uuid);}},fail: (err) => {console.error('获取服务失败', err);}});
}// 获取服务特征值
function getDeviceCharacteristics(deviceId, serviceId) {uni.getBLEDeviceCharacteristics({deviceId: deviceId,serviceId: serviceId,success: (res) => {console.log('获取特征值成功', res.characteristics);// 存储特征值信息,用于后续读写操作this.characteristics = res.characteristics;// 启用特征值变化的通知enableCharacteristicNotification(deviceId, serviceId, res.characteristics);},fail: (err) => {console.error('获取特征值失败', err);}});
}// 启用特征值变化的通知
function enableCharacteristicNotification(deviceId, serviceId, characteristics) {const notifyChar = characteristics.find(char => char.properties.notify);if (notifyChar) {uni.notifyBLECharacteristicValueChange({deviceId: deviceId,serviceId: serviceId,characteristicId: notifyChar.uuid,state: true,success: () => {console.log('启用通知成功');// 监听特征值变化uni.onBLECharacteristicValueChange(res => {console.log('特征值变化', res);// 处理接收到的数据const data = ab2hex(res.value);console.log('收到数据:', data);});},fail: (err) => {console.error('启用通知失败', err);}});}
}

5. 数据读写操作

通过特征值进行数据的写入和读取操作。

// 向设备写入数据
function writeDataToDevice(deviceId, serviceId, characteristicId, data) {// 将数据转换为ArrayBufferconst buffer = string2buffer(data);uni.writeBLECharacteristicValue({deviceId: deviceId,serviceId: serviceId,characteristicId: characteristicId,value: buffer,success: () => {console.log('写入数据成功');},fail: (err) => {console.error('写入数据失败', err);}});
}// 数据转换工具函数
function string2buffer(str) {let buf = new ArrayBuffer(str.length);let bufView = new Uint8Array(buf);for (let i = 0; i < str.length; i++) {bufView[i] = str.charCodeAt(i);}return buf;
}function ab2hex(buffer) {const hexArr = Array.prototype.map.call(new Uint8Array(buffer),function(bit) {return ('00' + bit.toString(16)).slice(-2);});return hexArr.join('');
}

三、完整实现示例

1. 页面结构 (index.vue)

<template><view class="container"><button @click="initBluetooth">初始化蓝牙</button><button @click="searchBluetoothDevices">搜索设备</button><view v-if="deviceList.length > 0"><view v-for="(device, index) in deviceList" :key="index" @click="connectDevice(device.deviceId)">{{ device.name || device.localName || '未知设备' }} - {{ device.deviceId }}</view></view><button @click="sendData" :disabled="!currentDevice">发送测试数据</button></view>
</template>

2. 脚本部分 (index.vue)

<script>
export default {data() {return {deviceList: [],currentDevice: null,currentServiceId: '',currentCharacteristicId: ''}},methods: {// 初始化蓝牙适配器initBluetooth() {uni.openBluetoothAdapter({success: (res) => {console.log('蓝牙适配器初始化成功', res);uni.showToast({ title: '蓝牙初始化成功', icon: 'success' });},fail: (err) => {console.error('蓝牙适配器初始化失败', err);uni.showToast({ title: '蓝牙初始化失败', icon: 'none' });}});},// 搜索蓝牙设备searchBluetoothDevices() {uni.startBluetoothDevicesDiscovery({allowDuplicatesKey: false,success: (res) => {console.log('开始搜索蓝牙设备', res);uni.showLoading({ title: '正在搜索设备...' });// 监听找到新设备的事件this.deviceFoundListener = uni.onBluetoothDeviceFound((devices) => {this.handleFoundDevices(devices);});// 15秒后超时停止搜索setTimeout(() => {this.stopBluetoothSearch();if (this.deviceList.length === 0) {uni.showModal({title: '提示',content: '未找到蓝牙设备',showCancel: false});}}, 15000);},fail: (err) => {console.error('开始搜索设备失败', err);uni.hideLoading();}});},// 处理找到的设备handleFoundDevices(devices) {const foundDevices = [];devices.devices.forEach(device => {if (device.name && device.name.includes('目标设备关键字')) {foundDevices.push(device);}});if (foundDevices.length > 0) {// 去重处理const uniqueDevices = [...new Map(foundDevices.map(item => [item.deviceId, item])).values()];this.deviceList = [...this.deviceList, ...uniqueDevices].filter((item, index, self) => index === self.findIndex(t => t.deviceId === item.deviceId));}},// 停止搜索蓝牙设备stopBluetoothSearch() {uni.stopBluetoothDevicesDiscovery({success: () => {uni.hideLoading();if (this.deviceFoundListener) {uni.offBluetoothDeviceFound(this.deviceFoundListener);}}});},// 连接设备connectDevice(deviceId) {uni.createBLEConnection({deviceId: deviceId,success: (res) => {console.log('连接设备成功', res);this.currentDevice = deviceId;uni.showToast({ title: '连接成功', icon: 'success' });// 连接成功后获取设备服务this.getDeviceServices(deviceId);},fail: (err) => {console.error('连接设备失败', err);uni.showToast({ title: '连接失败', icon: 'none' });}});},// 获取设备服务getDeviceServices(deviceId) {uni.getBLEDeviceServices({deviceId: deviceId,success: (res) => {console.log('获取服务成功', res.services);const targetService = res.services.find(service => service.uuid === '目标服务UUID');if (targetService) {this.currentServiceId = targetService.uuid;this.getDeviceCharacteristics(deviceId, targetService.uuid);}},fail: (err) => {console.error('获取服务失败', err);}});},// 获取服务特征值getDeviceCharacteristics(deviceId, serviceId) {uni.getBLEDeviceCharacteristics({deviceId: deviceId,serviceId: serviceId,success: (res) => {console.log('获取特征值成功', res.characteristics);const notifyChar = res.characteristics.find(char => char.properties.notify);const writeChar = res.characteristics.find(char => char.properties.write);if (notifyChar) {this.enableCharacteristicNotification(deviceId, serviceId, notifyChar.uuid);}if (writeChar) {this.currentCharacteristicId = writeChar.uuid;}},fail: (err) => {console.error('获取特征值失败', err);}});},// 启用特征值变化的通知enableCharacteristicNotification(deviceId, serviceId, characteristicId) {uni.notifyBLECharacteristicValueChange({deviceId: deviceId,serviceId: serviceId,characteristicId: characteristicId,state: true,success: () => {console.log('启用通知成功');this.characteristicChangeListener = uni.onBLECharacteristicValueChange(res => {console.log('特征值变化', res);const data = this.ab2hex(res.value);console.log('收到数据:', data);});},fail: (err) => {console.error('启用通知失败', err);}});},// 发送测试数据sendData() {if (!this.currentDevice || !this.currentServiceId || !this.currentCharacteristicId) {uni.showToast({ title: '请先连接设备', icon: 'none' });return;}const testData = 'Hello Bluetooth!';const buffer = this.string2buffer(testData);uni.writeBLECharacteristicValue({deviceId: this.currentDevice,serviceId: this.currentServiceId,characteristicId: this.currentCharacteristicId,value: buffer,success: () => {console.log('写入数据成功');uni.showToast({ title: '发送成功', icon: 'success' });},fail: (err) => {console.error('写入数据失败', err);uni.showToast({ title: '发送失败', icon: 'none' });}});},// 数据转换工具函数string2buffer(str) {let buf = new ArrayBuffer(str.length);let bufView = new Uint8Array(buf);for (let i = 0; i < str.length; i++) {bufView[i] = str.charCodeAt(i);}return buf;},ab2hex(buffer) {const hexArr = Array.prototype.map.call(new Uint8Array(buffer),function(bit) {return ('00' + bit.toString(16)).slice(-2);});return hexArr.join('');}},beforeDestroy() {// 组件销毁前清理蓝牙资源if (this.currentDevice) {uni.closeBLEConnection({deviceId: this.currentDevice});}if (this.deviceFoundListener) {uni.offBluetoothDeviceFound(this.deviceFoundListener);}if (this.characteristicChangeListener) {uni.offBLECharacteristicValueChange(this.characteristicChangeListener);}}
}
</script>

3. 样式部分 (index.vue)

<style>
.container {padding: 20px;
}button {margin: 10px 0;background-color: #07C160;color: white;border: none;padding: 10px 15px;border-radius: 5px;
}view {margin: 10px 0;padding: 10px;border: 1px solid #eee;border-radius: 5px;
}
</style>

四、注意事项

  1. 权限配置:在微信小程序中,需要在app.json中声明蓝牙权限:

    {"permission": {"scope.bluetooth": {"desc": "需要蓝牙权限以连接设备"}}
    }
    
  2. iOS与Android差异

    • iOS设备不支持获取MAC地址,如需MAC地址,需要设备厂商将MAC地址放在广播数据中[9]
    • Android设备需要定位权限才能搜索蓝牙设备[9]
  3. 连接稳定性

    • 蓝牙连接可能随时断开,建议监听onBLEConnectionStateChange事件进行重连处理[10]
    • 避免多次调用createBLEConnection创建重复连接[10]
  4. 数据传输限制

    • 单次写入数据建议不超过20字节[4]
    • 蓝牙4.0设备对单次传输数据大小有限制,超过可能导致写入错误[4]
  5. 资源释放

    • 页面销毁或不再需要蓝牙功能时,应调用closeBLEConnectioncloseBluetoothAdapter释放资源[10]

五、总结

通过本文的介绍,我们了解了在uni-app框架下实现微信小程序蓝牙连接的全过程。从初始化蓝牙模块、搜索设备、连接设备到数据交互,每个步骤都有详细的代码示例和说明。

主要实现步骤包括:

  1. 使用uni.openBluetoothAdapter()初始化蓝牙适配器
  2. 使用uni.startBluetoothDevicesDiscovery()搜索设备
  3. 使用uni.createBLEConnection()连接设备
  4. 获取设备服务和特征值
  5. 通过特征值进行数据读写操作

在实际开发中,还需要注意权限配置、平台差异、连接稳定性和资源释放等问题。希望本文的内容能帮助开发者快速掌握uni-app蓝牙开发技术,开发出功能完善的蓝牙应用。


文章转载自:

http://pvXz2wOC.rzrbw.cn
http://ZShnE0ph.rzrbw.cn
http://WxrMY0EU.rzrbw.cn
http://1Cj24sHz.rzrbw.cn
http://9QriDKOi.rzrbw.cn
http://sN8kBInn.rzrbw.cn
http://mCEDrEvq.rzrbw.cn
http://m5xgZzH1.rzrbw.cn
http://lrZlfKCn.rzrbw.cn
http://pk6PvEVx.rzrbw.cn
http://n8FiqjAc.rzrbw.cn
http://pRgdtI4g.rzrbw.cn
http://opYf1z4F.rzrbw.cn
http://zu84CJXe.rzrbw.cn
http://sLdWs2y0.rzrbw.cn
http://01c9agzf.rzrbw.cn
http://v13yuYG6.rzrbw.cn
http://CFNBOsEL.rzrbw.cn
http://NAd4ZrXb.rzrbw.cn
http://KqPhmLnD.rzrbw.cn
http://49YPnyVV.rzrbw.cn
http://r4ouRq4C.rzrbw.cn
http://ApXAzAgW.rzrbw.cn
http://gTFZnvHN.rzrbw.cn
http://ows9ZLTq.rzrbw.cn
http://BHK5fs0P.rzrbw.cn
http://ytMIMZkV.rzrbw.cn
http://NaLidKl6.rzrbw.cn
http://mqiI19Pm.rzrbw.cn
http://x3QrHHNo.rzrbw.cn
http://www.dtcms.com/a/370164.html

相关文章:

  • 从 scheduler_tick 到上下文切换:深入解析 Linux 内核的 TIF_NEED_RESCHED 标志设置流程
  • 微前端框架性能对比与选型指南:从理论到实践
  • pyAutoGUI 模块主要功能介绍-(1)鼠标功能
  • Maven的介绍及基本使用
  • 使用 C# .NETCore 实现MongoDB
  • 2025年渗透测试面试题总结-55(题目+回答)
  • %前置模糊查询优化
  • 【架构艺术】变更风险防控架构嵌入决策降噪模块的方法
  • ElmentUI之DateTimePicker 日期时间选择器
  • RabbitMQ 入门与 Go 语言实践
  • [Upscayl图像增强] Electron主进程命令 | 进程间通信IPC
  • 80(HTTP默认端口)和8080端口(备用HTTP端口)区别
  • AI模型测评平台工程化实战十二讲(第一讲:从手工测试到系统化的觉醒)
  • FreeMarker快速入门指南
  • python的数据结构
  • Spark 中spark.implicits._ 中的 toDF和DataFrame 类本身的 toDF 方法
  • 基于Spark的中文文本情感分析系统研究
  • 《用 asyncio 构建异步任务队列:Python 并发编程的实战与思考》
  • Python+DRVT 从外部调用 Revit:批量创建梁(2)
  • 数据库原理及应用_数据库管理和保护_第5章数据库的安全性_理论部分
  • 开源OpenHarmony润开鸿HH-SCDAYU800A开发板开箱体验
  • 第27节:3D数据可视化与大规模地形渲染
  • 《云原生故障诊疗指南:从假活到配置漂移的根治方案》
  • illustrator插件大全 免费插件介绍 Ai设计插件集合 (5)
  • Kubernetes (k8s)
  • 交叉编译器介绍
  • 2025最新超详细FreeRTOS入门教程:第二章 FreeRTOS任务创建
  • Webpack热更新(HMR)底层原理详解
  • repo 学习教程
  • 54.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--新增功能--实现手机邮箱注册