微信小程序开发笔记[6]-蓝牙ble扫描设备

发布时间 2023-12-24 13:02:40作者: qsBye

摘要

使用微信小程序扫描BLE设备,找到指定设备后弹窗.

平台信息

  • 微信开发者工具Stable 1.06.2310080

原理

typescript+less开发模式

[https://developers.weixin.qq.com/miniprogram/dev/devtools/compilets.html]
[https://blog.csdn.net/Boale_H/article/details/121360082]
小程序代码包要求代码文件为 wxml / wxss / js / json / wxs。
如果我们希望使用 TypeScript 或 less 去开发小程序,就需要将 ts 文件或 less 文件编译成对应的 js 文件 或 wxss 文件,这个编译过程以前是需要开发者在工具外自行配置。
从开发者工具 1.05.2109101 以上开始,我们优化工具内置的编译模块,支持以编译插件的形式,扩展编译功能。
使用这种方式有两个好处:
项目内只需要创建 ts 文件即可,无需再生成同名的 js 文件。less 文件同理。
编译流程由开发者工具控制,按需编译,开发体验更好。
可在创建小程序项目时,选择对应的语言模板。 目前支持的语言模板有

  • TypeScript
  • TypeScript + Less
  • TypeScript + Sass

typescript的类型

[https://typescript.p6p.net]
[https://www.typescriptlang.org/docs/handbook/intro.html]
[https://jkchao.github.io/typescript-book-chinese/]
TypeScript 代码最明显的特征,就是为 JavaScript 变量加上了类型声明。
TypeScript(简称 TS)是微软公司开发的一种基于 JavaScript (简称 JS)语言的编程语言。

它的目的并不是创造一种全新语言,而是增强 JavaScript 的功能,使其更适合多人合作的企业级项目。

TypeScript 可以看成是 JavaScript 的超集(superset),即它继承了后者的全部语法,所有 JavaScript 脚本都可以当作 TypeScript 脚本(但是可能会报错),此外它再增加了一些自己的语法。

TypeScript 对 JavaScript 添加的最主要部分,就是一个独立的类型系统。

静态类型有很多好处,这也是 TypeScript 想要达到的目的。

(1)有利于代码的静态分析。

有了静态类型,不必运行代码,就可以确定变量的类型,从而推断代码有没有错误。这就叫做代码的静态分析。

这对于大型项目非常重要,单单在开发阶段运行静态检查,就可以发现很多问题,避免交付有问题的代码,大大降低了线上风险。

(2)有利于发现错误。

由于每个值、每个变量、每个运算符都有严格的类型约束,TypeScript 就能轻松发现拼写错误、语义错误和方法调用错误,节省程序员的时间。

第三方库如果没有提供类型声明文件,社区往往会提供。TypeScript 社区主要使用 DefinitelyTyped 仓库,各种类型声明文件都会提交到那里,已经包含了几千个第三方库。

这些声明文件都会作为一个单独的库,发布到 npm 的@types名称空间之下。比如,jQuery 的类型声明文件就发布成@types/jquery这个库,使用时安装这个库就可以了。

TypeScript 会自动加载node_modules/@types目录下的模块,但可以使用编译选项typeRoots改变这种行为。

当前模块如果包含自己的类型声明文件,可以在 package.json 文件里面添加一个types字段或typings字段,指明类型声明文件的位置。

举例来说,入口文件是main.d.ts,里面的接口定义在interfaces.d.ts,函数定义在functions.d.ts。那么,main.d.ts里面可以用三斜杠命令,加载后面两个文件。

三斜杠命令(///)是一个 TypeScript 编译器命令,用来指定编译器行为。它只能用在文件的头部,如果用在其他地方,会被当作普通的注释。另外,若一个文件中使用了三斜线命令,那么在三斜线命令之前只允许使用单行注释、多行注释和其他三斜线命令,否则三斜杠命令也会被当作普通的注释。

实现

核心代码

app.json

{
  "pages": [
    "pages/index/index",
    "pages/logs/logs",
    "pages/about/about"
  ],
  "window": {
    "navigationBarTextStyle": "black",
    "navigationStyle": "custom"
  },
  "style": "v2",
  "rendererOptions": {
    "skyline": {
      "defaultDisplayBlock": true,
      "disableABTest": true,
      "sdkVersionBegin": "3.0.0",
      "sdkVersionEnd": "15.255.255"
    }
  },
  "componentFramework": "glass-easel",
  "sitemapLocation": "sitemap.json",
  "lazyCodeLoading": "requiredComponents"
}

index.wxml

<button bindtap="btn8Handler" style="margin-top:1vh;">连接蓝牙</button>

index.ts

// index.ts
// 引入mdui
// const mdui = require('mdui')

// 获取应用实例
const app = getApp<IAppOption>()

// 组件命名空间
Component({
  data: {
    imageList: [""], // 用于存储选中的图片的本地文件路径
    is_ble_searching: false, // ble扫描状态
    ble_device_list: [] as WechatMiniprogram.BlueToothDevice[], // ble设备列表
  },// end data
  methods: {
    // 上传图片事件处理函数
    chooseImage: function() {  
      var that = this; // 延伸this的作用域
      // 这里是处理图片选择的代码  
      wx.chooseImage({  
        count: 1, // 默认9  
        sizeType: ['original'], // 可以指定是原图还是压缩图,默认二者都有  
        sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有  
        success: function (res) {  
          // 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片  
          that.setData({
            imageList: res.tempFilePaths, // 直接将选中的图片路径设置为imageList,而不是合并
          });
          that.setImageSrc(res.tempFilePaths[0]); // 设置选中的图片为originalImage元素的源
        }  
      })  
    },  // end chooseImage

    // 设置originalImage元素的源为选中的图片
    setImageSrc(src: string) {
      const query = wx.createSelectorQuery();
      query.select('#originalImage').fields({  }).exec((res) => {
        if (res[0]) {
          res[0].src = src; // 设置选中的图片路径为originalImage元素的源
        }
      });
    },// end setImageSrc

    // 按钮8事件处理函数
    btn8Handler: function(){
      var that = this; // 延伸this的作用域
      // 开始扫描蓝牙
      console.log("开始扫描蓝牙")
      wx.showToast({
        title: "扫描ble设备",
        icon: 'none',
      })

      that.BleSearch()

      // TODO:连接蓝牙并保持连接

    },// end btn8Handler

    // 按钮9事件处理函数
    btn9Handler: function(){
      // 关闭蓝牙连接

    },// end btn9Handler

    // 蓝牙ble搜索
    BleSearch: function () {
      var that = this // 作用域不同,所以需要把Page.this重命名
      // is_ble_searching变量为搜索状态
      // 如果没有在搜索,则进行搜索
      if (!that.data.is_ble_searching) {
        // 关闭蓝牙
        wx.closeBluetoothAdapter({
          complete: function (res) {
            console.log(res)
            // 开启蓝牙
            wx.openBluetoothAdapter({
              success: function (res) {
                console.log(res)
                // 获取蓝牙适配器状态
                wx.getBluetoothAdapterState({
                  success: function (res) {
                    console.log("蓝牙状态:"+res.available)
                  }
                })
                // 开始蓝牙设备发现
                wx.startBluetoothDevicesDiscovery({
                  allowDuplicatesKey: false,
                  success: function (res) {
                    console.log(res)
                    that.setData({
                      is_ble_searching: true,
                      ble_device_list: []
                    })
                  }
                })
              },

              fail: function (res) {
                console.log(res)
                wx.showModal({
                  title: '提示',
                  content: '请检查手机蓝牙是否打开',
                  showCancel: false,
                  success: function (res) {
                    that.setData({
                      is_ble_searching: false
                    })
                  }
                })
              } // end fail

            }) // end openBluetoothAdapter

          }, // end complete

          fail: function (res) {
            console.log(res)
            wx.showModal({
              title: '提示',
              content: '请检查手机蓝牙是否打开',
              showCancel: false,
              success: function (res) {
                that.setData({
                  is_ble_searching: false
                })
              }
            })
          } // end fail

        }) // end closeBluetoothAdapter
      }

      // 如果在搜索,则停止搜索
      else {
        // 停止蓝牙设备发现
        wx.stopBluetoothDevicesDiscovery({
          success: function (res) {
            console.log(res)
            that.setData({
              is_ble_searching: false
            })
          }
        })
      }

      // 蓝牙搜索到设备
    wx.onBluetoothDeviceFound(function (devices) {
      //剔除重复设备,兼容不同设备API的不同返回值
      var isnotexist = true

      // 设备类型2的返回结果
      if (devices.devices) {
        console.log("设备类型2")
        if (devices.devices[0].advertisData){
          // devices.devices[0].advertisData = app.buf2hex(devices.devices[0].advertisData)
        }
        else{
          // 清空数据
          devices.devices[0].advertisData = new ArrayBuffer(0);
        }
        console.log(devices.devices[0])
        for (var i = 0; i < that.data.ble_device_list.length; i++) {
          if (devices.devices[0].deviceId == that.data.ble_device_list[i].deviceId) {
            isnotexist = false
          }
        }
        if (isnotexist) {
          that.data.ble_device_list.push(devices.devices[0])

          // 匹配名称
          if(devices.devices[0].name == "sugardraw"){
            console.log("找到设备surgardraw");
            wx.showToast({
              title: '找到设备surgardraw',
            });
          }

        }
      }

      // 删除重复项后更新显示
      that.setData({
        ble_device_list: that.data.ble_device_list
      })
    })
    
    }, // end BleSearch

    // 隐藏小程序自动停止搜索
    hide: function () {
      console.log("进入hide")
      var that = this
      that.setData({
        ble_device_list: []
      })
      if (this.data.is_ble_searching) {
        wx.stopBluetoothDevicesDiscovery({
          success: function (res) {
            console.log(res)
            that.setData({
              is_ble_searching: false
            })
          }
        })
      }
  },// end onHide

  // 页面加载完成事件
  ready: function (options:any) {
    console.log("进入ready")
    var that = this
    that.setData({

    })
    wx.onBluetoothAdapterStateChange(function (res) {
      console.log(res)
      console.log("扫描状态:"+res.discovering)
      that.setData({
        is_ble_searching: res.discovering
      })
      if (!res.available) {
        that.setData({
          is_ble_searching: false
        })
      }
    })

  }, // end onLoad

  },// end methods
})// end Component

效果