微信小程序小票打印功能(以及中文乱码的解决)

因为业务需求,需要实现微信小程序连接热敏打印机打印小票。首先我要先知道微信小程序有没有蓝牙操作相关的API,然后就是如何蓝牙连接打印机,发送打印指令了。

通过查看小程序文档,我看到微信小程序是支持蓝牙操作的

小程序文档

但是我看到它有两个,低功耗蓝牙,蓝牙。蓝牙我们知道,低功耗蓝牙是什么东西,网上查了下,解释如下:
以前可能有蓝牙1.0、蓝牙2.0、蓝牙3.0、蓝牙4.0之类的以数字结尾的蓝牙版本号,而实际上,在最新的标准中,已经不再使用数字版本号作为蓝牙版本的区分了,取而代之的是经典蓝牙与低功耗蓝牙(BLE)这两种区别
低功耗蓝牙(Bluetooth Low Energy,或称Bluetooth LEBLE,旧商标Bluetooth Smart)也称低功耗蓝牙,是蓝牙技术联盟设计和销售的一种个人局域网技术,旨在用于医疗保健、运动健身、信标、安防、家庭娱乐等领域的新兴应用。相较经典蓝牙,低功耗蓝牙旨在保持同等通信范围的同时显著降低功耗和成本.

我要打印肯定要与打印机进行数据通信的,通过文档我看到,只有低功耗蓝牙里面有一个写和读的方法,那么微信就限定我只能通过低功耗蓝牙相关api进行与打印机相关交互,同时也限定了我的打印机也要支持低功耗蓝牙连接,幸运的是我的打印机是支持的。
接下来看怎么写代码了,官方给了我们一个蓝牙操作的demo,那我就直接在demo上改了。



点上面就能打开示例代码了。


demo显示界面

上面是demo界面,点击开始扫描就能收到周围的蓝牙了,我的打印机蓝牙也在搜索结果的列表里,我试了下,能够连接到我的打印机。
接下来我打印一段文字试试。
在index.js里面我改写了这个方法,我打印了一个hello world.
writeBLECharacteristicValue() {
    let str = "hello world";
    let dataBuffer = new ArrayBuffer(100)
    let dataView = new DataView(dataBuffer)
     for (var i = 0; i < str.length; i++) {
      dataView.setUint8(i, str.charAt(i).charCodeAt())
    }
    wx.writeBLECharacteristicValue({
      deviceId: this._deviceId,
      serviceId: this._serviceId,
      characteristicId: this._characteristicId,
      value: dataBuffer,
      success: function(res) {
        console.log('发送的数据:' + that.writeDatas)
        console.log('message发送成功')
      },
      fail: function(res) {
        console.log("data:" + res)
      },
      complete: function(res) {
        console.log("data:" + res)
      }
    })
}

打印结果:


打印结果

看到了打印成功,接下来我试了下中文

writeBLECharacteristicValue() {
    let str = "你好 世界";
    let dataBuffer = new ArrayBuffer(100)
    let dataView = new DataView(dataBuffer)
     for (var i = 0; i < str.length; i++) {
      dataView.setUint8(i, str.charAt(i).charCodeAt())
    }
    wx.writeBLECharacteristicValue({
      deviceId: this._deviceId,
      serviceId: this._serviceId,
      characteristicId: this._characteristicId,
      value: dataBuffer,
      success: function(res) {
        console.log('message发送成功')
      },
      fail: function(res) {
        console.log("data:" + res)
      },
      complete: function(res) {
        console.log("data:" + res)
      }
    })
}

打印结果:


这打的是什么鬼,乱码了。初步推断可能是编码问题,网上也收到了相关问题的一些解答。
小程序丨【已解决】蓝牙打印机打印中文乱码

说是我的中文编码不对,应该转成gbk,然后再转成16进制,最后发送给打印机,说是这么说,但是代码怎么写,这片文章没说。我记得js是没有转gbk的方法的,只能看看别人怎么搞得,还真找到一个人写的。
小程序蓝牙打印

赶紧放到我的代码里试了一下,运行后发现了一个问题:

这个gbk转换的代码怎么来的,通篇就这个一句话,并没有讲怎么来的,我推测他可能引入了一个库gbk相关的,于是接着搜索,还真有相关的库http://www.vuln.cn/2901
下载下来

下载后,打开这个库
库文件内容

这个该怎么放到小程序里面用呢,在下载页面我们看到了它的用法介绍

这个写法小程序里不能用啊,不支持这种使用方式啊。小程序只支持下面这样的

function send0X0A() {
  const buffer = new ArrayBuffer(1)
  const dataView = new DataView(buffer)
  dataView.setUint8(0, 0x0a)
  return buffer;
}

定义方法的地方模块导出
module.exports = {
  hexStringToArrayBuffer: hexStringToArrayBuffer,
  hexStringToBuff: hexStringToBuff,
  send0X0A: send0X0A
}

使用的地方要引用一下
var util = require('../../utils/util.js');

没办法,只能修改库,一顿操作猛如虎,搞成了下面这样的



这里我只导出了一个编码的方法,调用的地方是这样使用的

const gbk = require('./gbk.js');
const hexStringToBuff = str => { //str='中国:WXHSH'
  const buffer = new ArrayBuffer((sumStrLength(str)) * 4)
  const dataView = new DataView(buffer)
  var data = str.toString();
  var p = 0; //ArrayBuffer 偏移量
  for (var i = 0; i < data.length; i++) {
    if (isCN(data[i])) { //是中文
      //调用GBK 转码
      var t = gbk.encode(data[i]);
      for (var j = 0; j < 2; j++) {
        var code = t[j * 2] + t[j * 2 + 1];
        var temp = parseInt(code, 16)
        dataView.setUint8(p++, temp)
      }
    } else {
      var temp = data.charCodeAt(i);
      dataView.setUint8(p++, temp)
    }
  }
  return buffer;
}
}

运行结果:图我就不截了,直接说结果,结果就是啥也没打印出来,这是怎么回事呢,调试下看看。



发现问题了,一个中文是占两个字节的%C4%C3,按照上面那个哥们的写法我只分割了%C,4%,这是什么鬼,应该是%C4,%C3,才对,两个各代表一个字节码编号。于是改了下代码:

const hexStringToBuff = str => { //str='中国:WXHSH'
  const buffer = new ArrayBuffer((sumStrLength(str)) * 4)
  const dataView = new DataView(buffer)
  var data = str.toString();
  var p = 0; //ArrayBuffer 偏移量
  for (var i = 0; i < data.length; i++) {
    if (isCN(data[i])) { //是中文
      //调用GBK 转码
      var t = gbk.encode(data[i]);
      for (var j = 0; j < 2; j++) {
        //var code = t[j * 2] + t[j * 2 + 1];
        var code = t[j * 3 + 1] + t[j * 3 + 2];
        var temp = parseInt(code, 16)
        dataView.setUint8(p++, temp)
      }
    } else {
      var temp = data.charCodeAt(i);
      dataView.setUint8(p++, temp)
    }
  }
  return buffer;
}

再次调试运行下看看:



嗯这下 算分割对了,但是打印机还是没反应,在看代码发现temp = NaN,这是怎么回事呢,于是网上搜索gbk转16进制,总共发现这两个可用的方法

function toUnicode(s) {
  var str = "";
  for (var i = 0; i < s.length; i++) {
    str += "\\u" + s.charCodeAt(i).toString(16) + "\t";
  }
  return str;
}

function strToHexCharCode(str) {
  if (str === "")
    return "";
  var hexCharCode = [];
  hexCharCode.push("0x");
  for (var i = 0; i < str.length; i++) {
    hexCharCode.push((str.charCodeAt(i)).toString(16));
  }
  return hexCharCode.join("");
}

调用其中一个看一下



哎呀,这回好像temp有值了,还是16进制的,赶紧通过断点,看看打印机反应,乖乖有反应了,不截图了,直接说结果吧,乱码 乱码 乱码,这就奇了怪了,都转好了,怎么还打印不出来呢。网上一顿搜也没什么结果, 静下心来想一想,之前我们App是有打印功能的,那App传输的数据是什么样的呢,对比下我传的有什么不一样么?



这个是android程序,它是通过getBytes()获取文本字节流。运行程序,查看打印结果

我发现 android 转出来的都是负的整数,不像我传的0x...... ,看来还是我的数据转换的不对,再看一眼调试页面。



C4 E3,貌似是十六进制数据,%号什么鬼,它不可能转成整型,temp 一直是NaN,得 我去掉%号试试。

呀嘿,temp有值了,跟Android的数据差不多,都是整数。过掉断点看看。

哈哈,出来了,这一刻的心情你懂的。

到此 小程序蓝牙打印算是流程搞通了,网上资料有时候不太全,有时还有错误,这就需要我们大胆猜测勇敢验证,最后福利来了,我把完整demo贡献上。
https://github.com/lerpo/bluethooth.git

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,099评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,473评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,229评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,570评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,427评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,335评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,737评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,392评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,693评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,730评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,512评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,349评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,750评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,017评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,290评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,706评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,904评论 2 335

推荐阅读更多精彩内容

  • 每天坚持记录自己的成长,是特别美好的一件事。这样的一天下来,是充实的,对今天有一个很好的梳理,同时,对明天又多了...
    陆宁阅读 408评论 0 0
  • 贺变丽 焦点解决初级10期 洛阳 坚持分享第49天 2018--07--30 这两天约练了两次(第1...
    hebl阅读 998评论 0 1
  • 1960年初秋午后,阳光暖洋洋的洒下来。 敬礼老汉看着坑里那碎金似的太阳的倒影随着轻风吹拂,微微的摇荡起来。摇起了...
    小扬少爷阅读 375评论 2 6
  • “外面没有别人,只有自己”这是张德芬说的一句话,说的挺好的。 当你在和世界上事物有联系时,你和他们相处的状态,很多...
    莉萍LP阅读 161评论 0 0
  • 守规则!想起旅游的一件事:导游每次都把集合时间说好几遍!但是总有以各种理由迟到的!有次游西湖,导游说好一点二十集合...
    Sabrinazou阅读 168评论 0 1