小程序蓝牙通信

news2024/11/26 16:59:56

蓝牙通信能力封装

一开始是根据uniapp提供的蓝牙api写的蓝牙方法,之后发现复用性,以及一些状态的监听存在缺陷,之后整理成了类。这样复用性以及状态监听的问题就解决了。

蓝牙组件

创建蓝牙组件的类

在这里插入图片描述

单例模式是为了保证蓝牙长连接,只有一个蓝牙实例

// 单例模式
    if (Bluetooth.instance) {
      return Bluetooth.instance;
    }
    Bluetooth.instance = this;

根据需求定义变量
const serviceUUID = “”; // 主服务的UUID
const notifyUUID = “”; // 读
const writeUUID = “”; // 写
这一部分,连接蓝牙uuid是必须的,可以考虑接受参数的形式,或者在类里面写好,两种方式

根据需要传入相应的回调方法
successLinkFn:蓝牙连接成功的回调
dataChangeFn:成功接收蓝牙指令的回调
blueToothLinkStatusFn :监听蓝牙状态的回调

export class Bluetooth {
  constructor(params) {
    // 单例模式
    if (Bluetooth.instance) {
      return Bluetooth.instance;
    }
    this.bundleData = null; // 需要拼包的数据
    this.BLTdeviceId = ""; // 设备的 id
    this.deviceId = params.deviceId; // 设备号(设备序列号)
    this.serviceUUID = params.serviceUUID || serviceUUID;
    this.notifyUUID = params.notifyUUID || notifyUUID;
    this.writeUUID = params.writeUUID || writeUUID;
    this.successLinkFn = params.successLinkFn; // 蓝牙连接成功
    this.dataChangeFn = params.dataChangeFn; // 接收蓝牙指令
    this.blueToothLinkStatusFn = params.blueToothLinkStatusFn; // 蓝牙连接状态
    this.initBluetooth();
    Bluetooth.instance = this;
  }
 }

初始化蓝牙

initBluetooth() {
    let _this = this;
    uni.openBluetoothAdapter({
      success(res) {
        console.log("初始化蓝牙成功", res);
        _this.getBluetoothAdapterState();
      },
      fail(error) {
        console.log(error);
      },
    });
  }

判断手机蓝牙标识是否打开的状态

  // 判断手机蓝牙标识是否打开的状态
  getBluetoothAdapterState() {
    const _this = this;
    uni.getBluetoothAdapterState({
      success(res) {
        //如果res.avaliable==false 说明没打开蓝牙 反之则打开
        if (res.available) {
          // 蓝牙打开-----开始搜寻附近蓝牙
          _this.startBluetoothDevicesDiscovery();
        } else {
          uni.showModal({
            content:
              "当前手机蓝牙关闭,请在手机设置中开启蓝牙,并允许微信获取您的蓝牙权限",
            confirmColor: "#4AC596",
            confirmText: "确定",
            showCancel: false,
            success(res) {},
            fail() {
              // TODO 蓝牙打开失败
              // 页面返回
              uni.navigateBack({
                delta: 1, //返回层数,2则上上页
              });
            },
          });
        }
      },
    });
  }

搜寻附近的蓝牙外围设备

  // 搜寻附近的蓝牙外围设备
  // 此操作比较耗费系统资源,请在搜索并连接到设备后调用 uni.stopBluetoothDevicesDiscovery 方法停止搜索。
  startBluetoothDevicesDiscovery() {
    let _this = this;
    uni.startBluetoothDevicesDiscovery({
      success(res) {
        console.log(res);
        _this.onBluetoothDeviceFound();
      },
      fail: function(res) {
        uni.showToast({
          title: "搜寻附近的蓝牙外围设备失败",
          icon: "none",
          duration: 1000,
        });
        console.log("搜寻附近的蓝牙外围设备失败");
      },
    });
  }

发现蓝牙设备(匹配要连接的蓝牙设备)

根据传入的设备序列号(设备号)进行匹配

  onBluetoothDeviceFound() {
    let _this = this;
    uni.onBluetoothDeviceFound(function(res) {
      res.devices.forEach(function(device) {
        let deviceName = device.localName || device.name;
        if (_this.deviceId == deviceName) { //根据传入的设备序列号(设备号)进行匹配
          console.log("发现蓝牙设备", device);
          _this.BLTdeviceId = device.deviceId;
          _this.startBluetoothDevicesDiscovery();
          _this.connectDevice();
        }
      });
    });
  }

连接蓝牙

  //连接蓝牙
  connectDevice() {
    let _this = this;
    uni.createBLEConnection({
      deviceId: _this.BLTdeviceId,
      timeout: 3000,
      success: function(res) {
        uni.showToast({
          icon: "success",
          title: "蓝牙连接成功",
          mask: true,
          duration: 3000,
        });
        console.log("蓝牙连接成功");
        _this.getBLEDeviceServices();
        // 监听蓝牙状态
        _this.blueToothLinkChange();
      },
      fail: function(res) {
        console.log("连接失败" + JSON.stringify(res));
        uni.showToast({
          icon: "none",
          title: "未成功连接设备,请重新搜索",
          mask: true,
          duration: 3000,
        });
      },
    });
  }

监听蓝牙状态

  // 监听蓝牙状态
  blueToothLinkChange() {
    const _this = this;
    uni.onBLEConnectionStateChange(function(res) {
      // 该方法回调中可以用于处理连接意外断开等异常情况
      console.log(
        `device ${res.deviceId} state has changed, connected: ${res.connected}`
      );
      _this.blueToothLinkStatusFn && _this.blueToothLinkStatusFn(res);
    });
  }

获取服务

  // 获取服务
  getBLEDeviceServices() {
    uni.showToast({
      icon: "none",
      title: "数据处理中,请稍后",
      duration: 3000,
      mask: true,
    });
    let _this = this;
    uni.getBLEDeviceServices({
      deviceId: _this.BLTdeviceId,
      success: function(res) {
        for (let i = 0; i < res.services.length; i++) {
          if (res.services[i].uuid == _this.serviceUUID) {
            console.log("获取serviceId成功", res);
            _this.getBLEDeviceCharacteristics();
            break;
          }
        }
      },
      fail: function(res) {
        console.log("获取serviceId失败", res);
        uni.showToast({
          icon: "none",
          title: "未成功连接设备,请重新搜索",
          mask: true,
          duration: 3000,
        });
      },
    });
  }

获取特征值

  // 获取特征值
  getBLEDeviceCharacteristics() {
    let _this = this;
    // 如果是自动链接的话,wx.getBLEDeviceCharacteristics方法建议使用setTimeout延迟1秒后再执行
    wx.getBLEDeviceCharacteristics({
      deviceId: _this.BLTdeviceId,
      serviceId: _this.serviceUUID,
      success(res) {
        console.log("获取特征值成功: ", res); // 可以在此判断特征值是否支持读写等操作,特征值其实也需要提前向硬件佬索取的
        _this.notify();
      },
      fail(err) {
        console.error(err);
        _this.closeBLEConnection();
        uni.showToast({
          title: "获取特征值失败",
          icon: "error",
        });
      },
    });
  }

开启消息监听(只使用一次)

  // 开启消息监听,只使用一次
  notify() {
    let _this = this;
    uni.notifyBLECharacteristicValueChange({
      state: true,
      deviceId: _this.BLTdeviceId, // 设备id
      serviceId: _this.serviceUUID, // 监听指定的服务
      characteristicId: _this.notifyUUID, // 监听对应的特征值
      type: "notification",
      success(res) {
        console.log("已开启监听: ", res);
        _this.successLinkFn && _this.successLinkFn("success");
      },
      fail(err) {
        console.error(err);
        _this.closeBLEConnection();
        uni.showToast({
          title: "监听失败",
          icon: "error",
        });
        console.log("监听失败");
      },
    });
  }

发送数据,只要有指令发送就会使用

根据蓝牙协议处理需要发送的数据,处理数据属于业务代码,处理好了直接调用send方法即可。

  // 发送数据,只要有指令发送就会使用
  send(data) {
    // 向蓝牙设备发送
    const _this = this;
    let buffer = Util.string2buffer(data);
    const BLTdeviceId = wx.getStorageSync("BLTdeviceId");
    wx.writeBLECharacteristicValue({
      deviceId: _this.BLTdeviceId,
      serviceId: _this.serviceUUID,
      characteristicId: _this.writeUUID,
      value: buffer,
      writeType: "writeNoResponse",
      success(res) {
        console.log("指令发送成功:", res);
        setTimeout(() => {
          _this.listenValueChange();
        }, 500);
      },
      fail(err) {
        console.error(err);
        _this.closeBLEConnection();
      },
    });
  }

监听消息变化

  // 监听消息变化
  listenValueChange() {
    const _this = this;
    uni.onBLECharacteristicValueChange((res) => {
      const data = Util.ab2hex(res.value);
      console.log("监听消息变化:", data);
      // 返回的数据有拆包的情况,所以需要判断data是否有帧头与帧尾,如无则需要拼接
      // 作为业务代码在回调方法中处理数据
      _this.dataChangeFn && _this.dataChangeFn(data, res);
    });
  }

蓝牙设备停止搜索

stopBluetoothDevicesDiscovery() {
    wx.stopBluetoothDevicesDiscovery({
      success(res) {
        console.log("蓝牙设备停止搜索:", res);
      },
    });
  }

断开蓝牙

// 断开蓝牙连接
  closeBLEConnection() {
    uni.closeBLEConnection({
      deviceId: _this.deviceId,
    });
    uni.closeBluetoothAdapter();
  }

使用蓝牙组件

在需要连接蓝牙的页面,调用Bluetooth的类,根据需要传入参数以及回调方式即可,可以在回调函数里面处理蓝牙数据,监听蓝牙连接状态

// 蓝牙连接
			handleBlueToothLink() {
				let _this = this
				let params = {
					deviceId: _this.deviceId,
					serviceUUID: "", // 主服务的UUID
					notifyUUID: "", // 读
					writeUUID: "", // 写
					successLinkFn: function(res) {
						_this.successLinkFn(res);
					},
					dataChangeFn: function(data, res) {
						_this.dataChangeFn(data, res);
					},
					blueToothLinkStatusFn: function(res) {
						_this.blueToothStatusChange(res);
					},
				};
				_this.blueTooth = new Bluetooth(params);
			},

发送蓝牙指令

在页面上点击按钮,发送对应的蓝牙指令,需要将指令处理为蓝牙协议需要的数据格式。

handlerClick(instruct, dataLen, data) {
	this.blueTooth.send(Util.instructData(instruct, dataLen, data));
},

由于处理蓝牙协议使用的方法很多 ,单独写在了util.js方法中进行调用,包含进制转换,帧头和帧尾的处理,补零,数据处理等方法。(本文中提供ArrayBuffer转换的方法,有需要的话,再提供)。

蓝牙传输需要ArrayBuffer格式的数据

// 将字符串转换成ArrayBufer
string2buffer(str) {
  let val = ""
  if(!str) return;
  let length = str.length;
  let index = 0;
  let array = []
  while(index < length){
    array.push(str.substring(index,index+2));
     index = index + 2;
  }
  val = array.join(",");
  // 将16进制转化为ArrayBuffer
  return new Uint8Array(val.match(/[\da-f]{2}/gi).map(function (h) {
    return parseInt(h, 16)
  })).buffer
},

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

  // ArrayBuffer转字符串
  arrayBufferToString(buffer) {
    return String.fromCharCode.apply(null, new Uint8Array(buffer));
  },

总结

蓝牙方法都是调用的uniapp提供的蓝牙api,按照文档来编写的。
类的封装是为了代码的复用性和组件化。以后再遇到蓝牙需求,可以直接使用BlueTooth的类。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/720526.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端(一)——前端开发遇到的普遍问题以及解决策略

&#x1f604;博主&#xff1a;小猫娃来啦 &#x1f604;文章核心&#xff1a;前端开发遇到的普遍问题以及解决策略 前端十万个为什么&#xff1f; 有人说vue框架是基于mvvm实现的&#xff1f;这种说法对吗&#xff1f; mvc和mvvm的区别是什么&#xff1f; mvvm是否是mvc的升…

内容文本生成二维码用excel表格导出(java)

内容文本生成二维码用excel表格导出(java) //若有问题可留言 效果如下: import java.io.ByteArrayOutputStream; import java.io.FileOutputStream; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map;import org.apache.po…

大厂股权就是这么“坑”,150万股票到账前被优化,损失惨重

某网友发文称&#xff1a;“自己还有47天就可以解锁股权&#xff0c;到时就有150万的股票到账&#xff0c;结果接到公司裁员通知&#xff0c;实在是淌血&#xff0c;我能反抗吗&#xff1f;” 对这我只能说&#xff0c;公司卡的就是这个点。所以大家在找工作的时候&#xff0c;…

SparkJDBC性能优化指南

前言 本文以Mysql为例。Spark作为一种强大且广泛应用于大数据处理的分布式计算框架,有着出色的性能和可伸缩性。在使用Spark处理大规模数据时,往往需要与关系型数据库MySQL进行交互。然而,由于MySQL和Spark本身的特性之间存在一些差异,直接使用Spark读写MySQL的默认配置可…

SQL 查找重复的电子邮箱

SQL 182 查找重复的电子邮箱 SQL架构 表: Person -------------------- | Column Name | Type | -------------------- | id | int | | email | varchar | -------------------- id 是该表的主键列。 此表的每一行都包含一封电子邮件。电子邮件不包含大写字母。 编写一个 SQ…

线性DP-入门篇

目录 数字三角形&#xff1a; 最长上升子序列&#xff1a; 魔族密码&#xff1a; 编辑距离&#xff1a; 线性动态规划的主要特点是状态转移的推导是按照问题规模 从小到大依次推导&#xff0c;较大规模的问题的解依赖较小规模的问题的解。 数字三角形&#xff1a; [USA…

大模型是什么

在计算机领域&#xff0c;大模型’是一个近年来备受关注的词汇。这篇文章旨在带你遨游大模型的世界&#xff0c;了解它们的特点、优缺点&#xff0c;以及需如何有效地利用它们。我们还会探讨一些具体的大模型实例&#xff0c;并分析其对人类社会的影响。 首先&#xff0c;我们…

Android Studio实现内容丰富的安卓博客发布平台

如需源码可以添加q-------3290510686&#xff0c;也有演示视频演示具体功能&#xff0c;源码不免费&#xff0c;尊重创作&#xff0c;尊重劳动。 项目编号078 1.开发环境 android stuido jdk1.8 eclipse mysql tomcat 2.功能介绍 安卓端&#xff1a; 1.注册登录 2.查看博客列表…

@项目经理:写好简历其实只要2步,保证你offer拿到手软!

早上好&#xff0c;我是老原。 混职场&#xff0c;最重要的是什么&#xff1f;还是能赚到钱。 有人说&#xff0c;重要的是开心。这么说吧&#xff0c;我身边那些赚得多的&#xff0c;没几个不开心的。 很多人赚不到钱&#xff0c;归结为自己能力差&#xff0c;不够努力。 …

年度好用的8款AI绘画工具,第1款一定要看

本文总结了8款2023年年度好用的AI绘画工具&#xff0c;它们结合了最新的技术和创新的设计理念&#xff0c;能帮助设计师将创意变为创作&#xff0c;一起来看看吧&#xff01; 1.即时AI灵感 即时AI灵感作为一款国产的AI绘图工具&#xff0c;采用了先进的自然语言处理和图像生成…

前端学习——jsDay2

运算符 赋值运算符 一元运算符 比较运算符 逻辑运算符 小练习 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name…

chatgpt实现NLP基本任务(实体识别、关系抽取、属性抽取、事件抽取、文本分类)

文章目录 前置&#xff1a;基础函数一、实体识别二、关系抽取三、属性抽取四、事件抽取五、文本分类六、可能存在的问题&#xff08;报错&#xff09; 前置&#xff1a;基础函数 import openai import time from tqdm import tqdmdef chatgpt_function(content, keyNone):open…

前端学习——jsDay1

Day1 JavaScript是什么&#xff1f; 实现点击按钮改变颜色 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"…

vue 移动端开发vw适配方案rem适配方案 + vant框架 + unocss|tailwindcss

写在前面的话&#xff1a;看了这篇文章&#xff0c;有些东西名词啥的不懂的&#xff0c;或者有疑问的推荐百度&#xff0c;因为写的太多真的显得很啰嗦&#xff01; 1.移动端开发适配 目前移动端适配&#xff0c;在市面上主流适配方案无非就两种&#xff0c;rem方案和vw方案。…

大禹智库:下一代向量数据库————具备在线化,协作化,可视化,自动化和安全互信的向量数据库

目录 一、在线化 二、协作化 三、可视化 四、自动化 五、安全互信 结论&#xff1a; 行业分析报告&#xff1a;下一代向量数据库的特征 摘要&#xff1a; 向量数据库是一种用于存储和处理向量数据的数据库系统。随着人工智能和大数据技术的快速发展&#xff0c;向量数据…

原生js实现for循环占位符绑定数据,类似模拟vue循环渲染数据

let ar [{ label: 显示文本1, value: 1 },{ label: 显示文本2, value: 2 },{ label: 显示文本3, value: 3 },{ label: 显示文本4, value: 4 },{ label: 显示文本5, value: 5 },], html , tpl <p>{value}&#xff1a;{label}</p>, dom document.querySelector(&…

MySQL安装及使用图文教程(超详细版本)

1、下载 下载地址&#xff1a;MySQL :: Download MySQL Installer 本文选择安装包安装版本 2、 安装 1&#xff09;双击安装包启动安装程序&#xff0c;点击“Next”按钮&#xff0c;如下图&#xff1a; 2&#xff09;点击“Execute”按钮 3&#xff09;点击“Next”按钮 4&a…

PHP 校园新闻网站系统mysql数据库web结构apache计算机软件工程网页wamp

一、源码特点 PHP 校园新闻网站系统 是一套完善的web设计系统&#xff0c;对理解php编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 下载地址https://download.csdn.net/download/qq_41221322/87999771https://downlo…

leetcode 141.环形链表(快慢指针追击问题)

⭐️ 往期相关文章 &#x1f4ab;链接1&#xff1a;链表分割 &#x1f4ab;链接2&#xff1a;链表中倒数第k个结点(快慢指针问题) &#x1f4ab;链接3&#xff1a;leetcode 876.链表的中间结点(快慢指针问题) &#x1f4ab;链接4&#xff1a;leetcode 206.反转链表 &#x1f4…

Linux网络、磁盘、内存、日志监控

文章目录 1、CPU性能监控1.2、平均负载基础1.3、平均负载与 CPU 使用率1.4、监控命令top命令mpstat命令pidstat场景一&#xff1a;CPU 密集型进程场景二&#xff1a;I/O 密集型进程场景三&#xff1a;大量进程的场景1.5、CPU上下文切换1.6、 遇到CPU利用率高该如何排查1.7、根据…