微信小程序对接蓝牙设备连接

初始化蓝牙模块 wx.openBluetoothAdapter()
初始化完成后搜寻附近的蓝牙设备 wx.startBluetoothDevicesDiscovery()
监听寻找到新设备的事件 wx.onBluetoothDeviceFound()
在监听寻找到新设备的事件回调中获取所有蓝牙设备列表 wx.getBluetoothDevices()
连接低功耗蓝牙设备 wx.createBLEConnection()
连接成功后获取蓝牙设备服务 wx.getBLEDeviceServices()
在服务中取(notify=true || indicate=true) && write=true 的特征值的 uuid: wx.getBLEDeviceCharacteristics()
完成后停止搜寻 wx.stopBluetoothDevicesDiscovery()
向低功耗蓝牙设备特征值中写入二进制数据 wx.writeBLECharacteristicValue()
离开页面时取消蓝牙连接 wx.closeBLEConnection()
关闭蓝牙模块 wx.closeBluetoothAdapter()
获取mac地址

在使用蓝牙的过程中,我们需要获取蓝牙设备的Mac地址。在Android设备上,onBluetoothDeviceFound方法中,deviceId是蓝牙设备的Mac地址。而在 iOS设备上,deviceId则是蓝牙设备的uuid。我们想要在iOS设备上获取Mac地址,就需要自己想办法。
https://blog.csdn.net/qq_25430563/article/details/124557109

services 180A
{
    "errno":0,
    "deviceId":"17512E41-549B-037C-4B22-E46A0FF3BA45",
    "services":[
        { "isPrimary":true, "uuid":"49535343-FE7D-4AE5-8FA9-9FAFD205E455" },
        { "isPrimary":true, "uuid":"E7810A71-73AE-499D-8C15-FAA9AEF0C3F2" },
        { "isPrimary":true, "uuid":"000018F0-0000-1000-8000-00805F9B34FB" },
        { "isPrimary":true, "uuid":"0000180A-0000-1000-8000-00805F9B34FB" }
    ],
    "errMsg":"getBLEDeviceServices:ok", "errCode":0
}
getBLEDeviceCharacteristics 日志
{  "characteristics":[
        {
            "properties":{
                "writeDefault":false,
                "notify":true,
                "write":false,
                "indicate":false,
                "read":false,
                "writeNoResponse":false
            },
            "uuid":"49535343-1E4D-4BD9-BA61-23C647249616"
        },
        {
            "properties":{
                "writeDefault":true,
                "notify":false,
                "write":true,
                "indicate":false,
                "read":false,
                "writeNoResponse":true
            },
            "uuid":"49535343-8841-43F4-A8D4-ECBE34729BB3"
        }
    ],
    "deviceId":"17512E41-549B-037C-4B22-E46A0FF3BA45",
    "serviceId":"49535343-FE7D-4AE5-8FA9-9FAFD205E455",
    "errno":0,  "errMsg":"getBLEDeviceCharacteristics:ok",  "errCode":0
}

代码 蓝牙搜索

// index.js
// 获取应用实例
const app = getApp()
const PrinterJobs = require('../../printer/printerjobs')
const printerUtil = require('../../printer/printerutil')
Page({
  data: {
    deviceName: 'aaa',
    bleInputValue: 'Qsprinter', //P8J12204110019\r\n
    deviceId: '',
    bleDeviceList: [],
    serviceId: '',
    notifyId: '',//getCharacteId()
    writeId: '',
  },
  // 事件处理函数
  bindViewTap() {
    wx.navigateTo({
      url: '../logs/logs'
    })
  },
  onLoad() {
    //this.getAddressData()
  },
  //-------------------ble--------------------------------
  showToast(msg){
    wx.showToast({ title: msg, })
  },
  initBluetooth:function(){
    wx.openBluetoothAdapter({
      //mode: '',
      success: (res) =>{
        this.findBlueList();//2.0
      },
      fail: (res) =>{
        //如果手机上的蓝牙没有打开,可以提醒用户
        this.showToast('手机蓝牙没打开')
        console.log(res)
      }
    })
  },
  findBlueList: function(){
    wx.showLoading({ title: '搜索附近设备', })
    wx.startBluetoothDevicesDiscovery({ //该接口非常耗电
      //services: ['FEE7'],
      allowDuplicatesKey: false,
      interval: 0,
      success:(res) =>{
        console.log('discovery, 搜索所有设备: %s', JSON.stringify(res))
        this.getBlue()
      },
      fail:(res) =>{
        //wx.hideLoading()
        console.log('discovery, 搜索附近的蓝牙失败')
      }
    })
  },
  closeBlue: function(){
    wx.stopBluetoothDevicesDiscovery({ // 连接蓝牙成功之后关闭蓝牙搜索
      success: (res) => {
        console.log('close 关闭蓝牙搜索') //this.showToast('关闭蓝牙搜索')
      }
   })
  },
  getBlue: function(){
    wx.getBluetoothDevices({
      success: (res) => {
        //wx.hideLoading();
        console.log('devices, 搜到设备总数: %d, 打印列表: \n%s', res.devices.length, JSON.stringify(res.devices))
        //如果搜所到设备列表为空
        if(res.devices.length == 0){
          // 监听搜索到新设备
          wx.onBluetoothDeviceFound((bres) => {
            for(var i = 0; i < bres.devices.length; i++){
              let d = bres.devices[i]
              if(d.name=='' || d.name.startsWith('P8') || d.name.startsWith("未知设备") || d.name.startsWith('Xiao')){
                continue //过滤设备
              }
              if(d.name == this.data.bleInputValue || d.localName == this.data.bleInputValue){
                console.log('devs size 0,  getBluetooth, name:' + d.name)
                this.getBlue()
              }
            }
          })
          console.log('devs 0,-----------end')
          return
        }else{
          console.log('devs list, find ok -----------' + res.devices.length); //console.log(res.devices)
          this.setData({ bleDeviceList: res.devices })
          for(var i = 0; i < res.devices.length; i++){
            //判断列表中是否包含我的蓝牙设备
            var d = res.devices[i];
            if(d.name == this.data.bleInputValue){
              
              this.setData({ deviceId: d.deviceId })
              this.connectBlue(d)
              return
            }
          }
        }
      },
      fail: () => {
        console.log("devs 搜索蓝牙设备失败")
      }
    })
  },
  connectBlue(dev){
    var deviceId = this.data.deviceId
    var deviceName = dev.name + " " + deviceId;
    console.log("connect, 连接设备 name: %s, data: %s", deviceName, JSON.stringify(dev))
    this.showToast("正在连接: " + deviceName)
    //
    //this.createBLEConnection_test()
    //
    wx.createBLEConnection({
      deviceId: this.data.deviceId,
      success: (res) =>{
        console.log('connect, 蓝牙连接成功!' + deviceName)
        this.showToast("连接成功:" + deviceName)
        this.closeBlue()
        this.getServiceId()//5.0
      },
      fail: () => {
        this.showToast("连接失败: " + deviceName)
        console.log('connect, 连接失败 ' + deviceName)
      },
      complete: () =>{
        //wx.hideLoading();
      }
    })
  },
  getServiceId(){
    // 5 连接上需要的蓝牙设备之后,获取蓝牙设备的服务uuid
    console.log('获取蓝牙设备的serviceId')
    wx.getBLEDeviceServices({
      deviceId: this.data.deviceId,
      success: (res) => {
        console.log('serviceId, 列表 res: %s', JSON.stringify(res))

        var model = res.services[0]
          this.setData({ serviceId: model.uuid })
          console.log('serviceId, uuid: ' + model.uuid)
          this.getCharacteId()
       
        // // 使用包含 180A 的服务id
        // if (model.uuid.indexOf('180A')) {
        //   console.log('serviceId, 包含 180A 的服务id, uuid: ' + model.uuid)
        //   this.setData({ serviceId: model.uuid })
        //   this.getCharacteId() //6.0
        // }
        
      }
   })
  },
/**
 * 6.获取蓝牙设备某个服务中所有特征值(characteristic)
 * 如果一个蓝牙设备需要进行数据的写入以及数据传输,就必须具有某些特征值,所以通过上面步骤获取的id可以查看当前蓝牙设备的特征值
 * characteristic
 *     uuid:蓝牙设备特征值的 uuid
 *     properties:该特征值支持的操作类型
 */
  getCharacteId(){
    wx.getBLEDeviceCharacteristics({
      deviceId: this.data.deviceId,
      serviceId: this.data.serviceId,
      success: (res) =>{
        console.log('characteId, getBLEDeviceCharacteristics: ', JSON.stringify(res))
        for(let i = 0; i < res.characteristics.length; i++){ //2个特征值
          var model = res.characteristics[i]
          if(model.properties.notify){
            this.setData({ notifyId: model.uuid }) //监听的值
            console.log('characteId, notifyId 获取监听的值 , uuid: %s', model.uuid)
            this.startNotice(model.uuid)
          }
          if(model.properties.write){
            console.log('writeId, uuid: %s', model.uuid)
            this.setData({ writeId: model.uuid })  //用来写入的值
          }
           使用含有 2A23 对应的特征值
          // if (!model.uuid.indexOf('2A23')) {
          //   console.log('characteId, failed 找不到含有 2A23 对应的特征值,: %s', model.uuid)
          // }
          // if (model.uuid.indexOf('2A23')) {
          //   if(model.properties.notify == true){
          //     this.setData({notifyId: model.uuid }) //监听的值
          //     console.log('characteId, 使用含有 2A23 对应的特征值, 监听的值 characterId: %s', model.uuid)
          //     this.startNotice(model.uuid)
          //   }
          //   if(model.properties.write == true){
          //     console.log('writeId, uuid: %s', model.uuid)
          //     this.setData({ writeId: model.uuid }) //用来写入的值
          //   }
          // }
          
          wx.readBLECharacteristicValue({
            deviceId: this.data.deviceId,
            serviceId: this.data.serviceId,
            characteristicId: this.data.notifyId,
            success: res => {
              console.log('mac, readBLECharacteristicValue ----- res: %s', JSON.stringify(res))
            }
          })
        }
      }
    })
  },
  startNotice(uuid){
    console.log('startNotice uuid--------', uuid)
    wx.notifyBLECharacteristicValueChange({ //7.创建连接,发送指令
      state: true, // 启用 notify 功能
      deviceId: this.data.deviceId,
      serviceId: this.data.serviceId,
      characteristicId: uuid, //第一步 开启监听 notityid  第二步发送指令 write
      success: (res) => {
        console.log('write, notifyBLECharacteristicValueChange --- res: %s', JSON.stringify(res))

        // // 当特征值是查询 Mac 地址时 add
        // if (res.characteristicId.indexOf('2A23')) {
        //   let macInfo = (array2String(res.value)).toUpperCase()
        //   console.log('mac info ---2A23--------', macInfo)
        // }

        console.log('========== send start==========')

        this.sendPrinterJobsCommand();
  
        console.log('========== send end==========')
        //
        //设备返回的方法 // 监听低功耗蓝牙连接的错误事件
        wx.onBLECharacteristicValueChange((result) => {
          //此时可以拿到蓝牙设备返回来的数据是一个ArrayBuffer类型数据,所以需要通过一个方法转换成字符串
          var nonceId = this.ab2hex(result.value)
          console.log('onBLECharacteristicValueChange, get nonceId: %s,  result: %s', nonceId, JSON.stringify(result))
          拿到这个值后,要去后台请求服务(当前步骤根据当前需求自己书写),获取下一步操作指令写入到蓝牙设备上去
          // wx.request({
          //   url: url,
          //   method: 'POST',
          //   data:{ describe: nonceId },
          //   success: (result2) =>{
          //     console.log('request, result2: %s', JSON.stringify(result2))
          //     //res.data.data.ciphertext; 我这边的服务返回来的是16进制字符串,蓝牙设备是接收不到当前格式的数据,需要转换成ArrayBuffer
          //     this.onSendCommand(this.string2buffer(result2.data.data.ciphertext)) //8.0
          //     //服务器返回一个命令,我们要把这个命令写入蓝牙设备
          //   }
          // })
        })
      }
    })
  },
  onSendCommand(buffer){
    wx.writeBLECharacteristicValue({
        deviceId: this.data.deviceId,
        serviceId: this.data.serviceId,
        characteristicId: this.data.writeId,//第二步写入的特征值
        value: buffer, // 这里的value是ArrayBuffer类型
        success: (res) => {
          console.log('write, 写入成功 send ok, res: %s', JSON.stringify(res))
        },
        fail: () => {
          console.log('写入失败')
        },
        complete:() => {
          console.log("调用结束");
        }
     })
  },
  //下面是需要使用到的两个格式相互转换的方法
  // 将字符串转换成ArrayBufer
  string2buffer(str) {
    console.log("将字符串转换成ArrayBufer-----" + 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
  },

  //
  str2ArrayBuff(str) {
		// Convert str to ArrayBuff and write to printer
		let buffer = new ArrayBuffer(str.length)
		let dataView = new DataView(buffer)
		for (let i = 0; i < str.length; i++) {
			dataView.setUint8(i, str.charAt(i).charCodeAt(0))
		}
		return buffer;
  },
  
 // 将ArrayBuffer转换成字符串
  ab2hex(buffer) {
    console.log("将ArrayBuffer转换成字符串")
    var hexArr = Array.prototype.map.call(
      new Uint8Array(buffer),
      function (bit) {
        return ('00' + bit.toString(16)).slice(-2)
      }
    )
    return hexArr.join('');
  },
//
  array2String(buffer) {
    let hexArr = Array.prototype.map.call(
      new Uint8Array(buffer),
      function (bit) {
        return ('00' + bit.toString(16)).slice(-2)
      }
    )
    return `${hexArr[7]}:${hexArr[6]}:${hexArr[5]}:${hexArr[2]}:${hexArr[1]}:${hexArr[0]}`
  },

  sendPrinterJobsCommand(){
    let printerJobs = new PrinterJobs();
    printerJobs
      .print('2022年12月5日17:34')
      .print(printerUtil.fillLine())
      .setAlign('ct')
      .setSize(2, 2)
      .println('深圳市公安局交通警察支队南山大队\n违规停放机动车提示单')
      .setSize(1, 1)
      .print('切尔西Chelsea')
      .setSize(2, 2)
      .print('在线支付(已支付)')
      .setSize(1, 1)
      .print('订单号:5415221202244734')
      .print('下单时间:2022-12-05 18:08:08')
      .setAlign('lt')
      .print(printerUtil.fillAround('一号口袋'))
      .print(printerUtil.inline('意大利茄汁一面 * 1', '15'))
      .print(printerUtil.fillAround('其他'))
      .print('餐盒费:1')
      .print('[赠送康师傅冰红茶] * 1')
      .print(printerUtil.fillLine())
      .setAlign('rt')
      .print('原价:¥16')
      .print('总价:¥16')
      .setAlign('lt')
      .print(printerUtil.fillLine())
      .print('备注')
      .print("无")
      .print(printerUtil.fillLine())
      .println();
      //
      let buffer = printerJobs.buffer();
      console.log('ArrayBuffer', 'length: ' + buffer.byteLength, ' hex: ' + this.ab2hex(buffer));
      //this.onSendCommand(buffer);
      //

  },

 /**
  * 源代码 小票打印案例 参考
  */
  writeBLECharacteristicValue() {
    let printerJobs = new PrinterJobs();
    printerJobs
      .print('2018年12月5日17:34')
      .print(printerUtil.fillLine())
      .setAlign('ct')
      .setSize(2, 2)
      .println('#20饿了么外卖')
      .setSize(1, 1)
      .print('切尔西Chelsea')
      .setSize(2, 2)
      .print('在线支付(已支付)')
      .setSize(1, 1)
      .print('订单号:5415221202244734')
      .print('下单时间:2017-07-07 18:08:08')
      .setAlign('lt')
      .print(printerUtil.fillAround('一号口袋'))
      .print(printerUtil.inline('意大利茄汁一面 * 1', '15'))
      .print(printerUtil.fillAround('其他'))
      .print('餐盒费:1')
      .print('[赠送康师傅冰红茶] * 1')
      .print(printerUtil.fillLine())
      .setAlign('rt')
      .print('原价:¥16')
      .print('总价:¥16')
      .setAlign('lt')
      .print(printerUtil.fillLine())
      .print('备注')
      .print("无")
      .print(printerUtil.fillLine())
      .println();

    let buffer = printerJobs.buffer();
    console.log('ArrayBuffer', 'length: ' + buffer.byteLength, ' hex: ' + this.ab2hex(buffer));
    // 1.并行调用多次会存在写失败的可能性
    // 2.建议每次写入不超过20字节
    // 分包处理,延时调用
    const maxChunk = 20;
    const delay = 20;
    for (let i = 0, j = 0, length = buffer.byteLength; i < length; i += maxChunk, j++) {
      let subPackage = buffer.slice(i, i + maxChunk <= length ? (i + maxChunk) : length);
      setTimeout(this._writeBLECharacteristicValue, j * delay, subPackage);
    }
  },
  /**
   * 
   * @param {*} text 
   */
  printImageQrcode(text){
    //
  },
  //绘制二维码
  draw() {
      //设置text为二维码码值,一般通过接口获取后赋值
      let text = '123123' + Math.random(0,100);
      //设置倒计时为5秒 this.setData({ countDown: 5, })
      const query = wx.createSelectorQuery()
      let that = this
      query.select('#myQrcode')
        .fields({
          node: true,
          size: true
        })
        .exec(async (res) => {
          let canvas = res[0].node
          var img = canvas.createImage();
          //二维码中间那个小logo的地址
         img.src = 'https://profile.csdnimg.cn/D/5/5/1_luo1831251387'
          img.onload = function () {
            // img.onload完成后才能调用 drawQrcode方法
            var options = {
              canvas: canvas,
              canvasId: 'myQrcode',
              width: 350, 
              padding: 30,
              paddingColor: '#fff',
              background: '#fff',
              foreground:'rgb(0, 178, 106)' ,
              //值
              text: text,
              image: {
                imageResource: img,
                width: 70, // logo图片大小 建议不要设置过大,以免影响扫码
                height: 70, // 建议不要设置过大,以免影响扫码
                round: true // Logo图片是否为圆形
              }
            }
            drawQrcode(options)
            // 获取临时路径(得到之后,想干嘛就干嘛了)
            wx.canvasToTempFilePath({
              x: 0,
              y: 0,
              width: 350,
              height: 350,
              destWidth: 600,
              destHeight: 600,
              canvasId: 'myQrcode',
              canvas: canvas,
              success(res) {
                console.log('二维码临时路径为:', res.tempFilePath)
              },
              fail(res) {
                console.error(res)
              }
            })
          };
        })
  },




  //打印二维码
  printImgT(device, text) {//小票打印
    device = { "deviceId": this.data.deviceId, "serviceId": this.data.serviceId, "writeId": this.data.writeId }
  let tthis = this;
  const ctx = wx.createCanvasContext('canvas');
  ctx.clearRect(0, 0, 160, 160);
  drawQrcode({
    canvasId: 'canvas',
    text: String(text),
    width: 100,
    height: 100,
    callback(e) {
      setTimeout(() => {
        // 获取图片数据
        wx.canvasGetImageData({
          canvasId: 'canvas',
          x: 0,
          y: 0,
          width: 160,
          height: 160,
          success(res) {
            let arr = tthis.convert4to1(res.data);
            let data = tthis.convert8to1(arr);
            const cmds = [].concat([27, 97, 1], [29, 118, 48, 0, 20, 0, 160, 0], data, [27, 74, 3], [27, 64]);
            const buffer = toArrayBuffer(Buffer.from(cmds, 'gb2312'));
            let arrPrint = [];
            arrPrint.push(util.sendDirective([0x1B, 0x40]));
            // arrPrint.push(util.sendDirective([0x1B, 0x61, 0x01])); //居中
            for (let i = 0; i < buffer.byteLength; i = i + 20) {
              arrPrint.push(buffer.slice(i, i + 20));
            }
            arrPrint.push(util.hexStringToBuff("\n"));
            arrPrint.push(util.sendDirective([0x1B, 0x61, 0x01])); //居中
            arrPrint.push(util.hexStringToBuff("扫码识别订单号\n"));
            arrPrint.push(util.hexStringToBuff("\n"));
            arrPrint.push(util.hexStringToBuff("\n"));
            tthis.printInfo(device, arrPrint);
          }
        })
      }, 3000);
    }
  });
},

printInfo: function(device, arr, callback) {
  let tthis = this;
  if (arr.length > 0) {
    tthis.sendStr(device, arr[0], function(success) {
      arr.shift();
      tthis.printInfo(device, arr, callback);
    }, function(error) {
      console.log(error);
    });
  } else {
    callback ? callback() : '';
  }
},

//发送数据
sendStr: function(device, bufferstr, success, fail) {
  let tthis = this;
  console.log('sendStr', device);
  wx.writeBLECharacteristicValue({
    deviceId: device.deviceId,
    serviceId: device.serviceId,
    characteristicId: device.characteristicId,
    value: bufferstr,
    success: function(res) {
      success(res);
      console.log('sendStr', bufferstr)
    },
    failed: function(res) {
      fail(res)
      console.log("数据发送失败:" + JSON.stringify(res))
    },
    complete: function(res) {
    	console.log("发送完成:" + JSON.stringify(res))
    }
  })
},

//4合1
convert4to1(res) {
  let arr = [];
  for (let i = 0; i < res.length; i++) {
    if (i % 4 == 0) {
      let rule = 0.29900 * res[i] + 0.58700 * res[i + 1] + 0.11400 * res[i + 2];
      if (rule > 200) {
        res[i] = 0;
      } else {
        res[i] = 1;
      }
      arr.push(res[i]);
    }
  }
  return arr;
},

//8合1
convert8to1(arr) {
  let data = [];
  for (let k = 0; k < arr.length; k += 8) {
    let temp = arr[k] * 128 + arr[k + 1] * 64 + arr[k + 2] * 32 + arr[k + 3] * 16 + arr[k + 4] * 8 + arr[k + 5] * 4 +
      arr[k + 6] * 2 + arr[k + 7] * 1
    data.push(temp);
  }
  return data;
},

})

旧的版本 wx.createCanvasContext()

weapp.qrcode

微信小程序二维码生成工具 weapp.qrcode
https://blog.goodsunlc.com/archives/376.html
https://juejin.cn/post/6844903559251640328
https://www.cnblogs.com/huangguofeng/p/13735859.html

代码 printImgT()方法

wx-bluetooth
https://gitee.com/copperpeas/wx-bluetooth/blob/master/pages/index/index.js

PrinterJobs 工具下载

https://github.com/benioZhang/miniprogram-bluetoothprinter/tree/master/printer

扫普通链接二维码打开小程序

扫普通链接二维码打开小程序
https://developers.weixin.qq.com/miniprogram/introduction/qrcode.html#%E5%8A%9F%E8%83%BD%E4%BB%8B%E7%BB%8D

蓝牙

企业微信 蓝牙
https://developer.work.weixin.qq.com/document/path/90771

微信小程序对接蓝牙设备连接
https://blog.csdn.net/qq_43384836/article/details/121632237

https://blog.csdn.net/weixin_34200628/article/details/91391230?utm_medium=distribute.pc_relevant.none-task-blog-title-3&spm=1001.2101.3001.4242

Canvas 2D 绘制二维码

下载 weapp-qrcode-canvas-2d 示例代码(官网)

画布。2.9.0 起支持一套新 Canvas 2D 接口(需指定 type 属性),同时支持同层渲染

https://developers.weixin.qq.com/miniprogram/dev/component/canvas.html#Canvas-2D-%E7%A4%BA%E4%BE%8B%E4%BB%A3%E7%A0%81

二维码生成工具 weapp-qrcode-canvas-2d

gitee仓库地址 https://gitee.com/WeiDoctor/weapp-qrcode-canvas-2d

教程
https://developers.weixin.qq.com/community/develop/article/doc/000e88e73a415835ed9b46d7956013

案例2

微信小程序绘制二维码
https://blog.csdn.net/luo1831251387/article/details/125641264

https://blog.csdn.net/weixin_46899191/article/details/122237849
https://m.php.cn/article/487088.html

createSelectorQuery
getImageData 获取像素点数据

用canvas中的getImageData方法获取像素点数据
https://blog.csdn.net/qq_40129176/article/details/103600918

node null

创建’2d’canvas出现Cannot read ‘node’ of null的问题?
https://developers.weixin.qq.com/community/develop/doc/000caea9508b18e7c5f9581f258c00

热敏打印机编程 ESC/POS指令

https://www.jianshu.com/p/dd6ca0054298

小程序 canvas2d
https://blog.csdn.net/weixin_39685861/article/details/106033494

打印相关链接
### 打印二维码(old)

微信小程序蓝牙打印二维码 https://blog.csdn.net/cn_zgt_boss/article/details/104068404

wx.createCanvasContext方法已废弃的解决方案 https://blog.csdn.net/zs1028/article/details/124788038

微信小程序连接蓝牙打印小票
https://blog.csdn.net/LDL_CQ/article/details/122835290

微信小程序蓝牙对接热敏打印机
https://blog.csdn.net/qq_37970097/article/details/119148707

打印图片
微信小程序连接蓝牙打印机打印图片 https://blog.csdn.net/cn_zgt_boss/article/details/104068404
用微信小程序打印取件码标签 http://56diandian.com/wcx-dyqjm/

微信小程序实现蓝牙打印(图片、二维码、文字)
https://blog.csdn.net/sghu8023/article/details/116234704


小程序实现BLE蓝牙连接硬件设备
https://www.jianshu.com/p/0f4ff8a2249d
参考资料

微信官方文档 蓝牙
https://developers.weixin.qq.com/miniprogram/dev/framework/device/ble.html

微信小程序连接蓝牙设备并传递数据
https://blog.csdn.net/qq_41889034/article/details/123981966




Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐