因為業(yè)務需求,需要實現(xiàn)微信小程序連接熱敏打印機打印小票鄙皇。首先我要先知道微信小程序有沒有藍牙操作相關的API先巴,然后就是如何藍牙連接打印機短绸,發(fā)送打印指令了车吹。
通過查看小程序文檔,我看到微信小程序是支持藍牙操作的
但是我看到它有兩個醋闭,低功耗藍牙窄驹,藍牙。藍牙我們知道证逻,低功耗藍牙是什么東西乐埠,網(wǎng)上查了下,解釋如下:
以前可能有藍牙1.0囚企、藍牙2.0丈咐、藍牙3.0、藍牙4.0之類的以數(shù)字結尾的藍牙版本號龙宏,而實際上棵逊,在最新的標準中,已經(jīng)不再使用數(shù)字版本號作為藍牙版本的區(qū)分了银酗,取而代之的是經(jīng)典藍牙與低功耗藍牙(BLE)這兩種區(qū)別
低功耗藍牙(Bluetooth Low Energy辆影,或稱Bluetooth LE、BLE黍特,舊商標Bluetooth Smart)也稱低功耗藍牙蛙讥,是藍牙技術聯(lián)盟設計和銷售的一種個人局域網(wǎng)技術,旨在用于醫(yī)療保健灭衷、運動健身次慢、信標、安防翔曲、家庭娛樂等領域的新興應用迫像。相較經(jīng)典藍牙,低功耗藍牙旨在保持同等通信范圍的同時顯著降低功耗和成本.
我要打印肯定要與打印機進行數(shù)據(jù)通信的瞳遍,通過文檔我看到侵蒙,只有低功耗藍牙里面有一個寫和讀的方法,那么微信就限定我只能通過低功耗藍牙相關api進行與打印機相關交互傅蹂,同時也限定了我的打印機也要支持低功耗藍牙連接纷闺,幸運的是我的打印機是支持的。
接下來看怎么寫代碼了份蝴,官方給了我們一個藍牙操作的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('發(fā)送的數(shù)據(jù):' + that.writeDatas)
console.log('message發(fā)送成功')
},
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發(fā)送成功')
},
fail: function(res) {
console.log("data:" + res)
},
complete: function(res) {
console.log("data:" + res)
}
})
}
打印結果:
這打的是什么鬼怒医,亂碼了炉抒。初步推斷可能是編碼問題,網(wǎng)上也收到了相關問題的一些解答稚叹。
小程序丨【已解決】藍牙打印機打印中文亂碼
說是我的中文編碼不對焰薄,應該轉成gbk,然后再轉成16進制扒袖,最后發(fā)送給打印機塞茅,說是這么說,但是代碼怎么寫季率,這片文章沒說野瘦。我記得js是沒有轉gbk的方法的,只能看看別人怎么搞得飒泻,還真找到一個人寫的鞭光。
小程序藍牙打印
趕緊放到我的代碼里試了一下,運行后發(fā)現(xiàn)了一個問題:
這個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;
}
}
運行結果:圖我就不截了,直接說結果垢村,結果就是啥也沒打印出來,這是怎么回事呢侵佃,調試下看看。
發(fā)現(xiàn)問題了,一個中文是占兩個字節(jié)的%C4%C3,按照上面那個哥們的寫法我只分割了%C,4%烙常,這是什么鬼蚕脏,應該是%C4秦驯,%C3译隘,才對,兩個各代表一個字節(jié)碼編號厅目。于是改了下代碼:
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;
}
再次調試運行下看看:
嗯這下 算分割對了深啤,但是打印機還是沒反應诱桂,在看代碼發(fā)現(xiàn)temp = NaN,這是怎么回事呢访诱,于是網(wǎng)上搜索gbk轉16進制九榔,總共發(fā)現(xiàn)這兩個可用的方法
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進制的缰冤,趕緊通過斷點怀薛,看看打印機反應,乖乖有反應了,不截圖了呐能,直接說結果吧摆出,亂碼 亂碼 亂碼,這就奇了怪了,都轉好了,怎么還打印不出來呢。網(wǎng)上一頓搜也沒什么結果泌射, 靜下心來想一想豺裆,之前我們App是有打印功能的躺酒,那App傳輸?shù)臄?shù)據(jù)是什么樣的呢,對比下我傳的有什么不一樣么?
這個是android程序累颂,它是通過getBytes()獲取文本字節(jié)流。運行程序,查看打印結果
我發(fā)現(xiàn) android 轉出來的都是負的整數(shù)悦荒,不像我傳的0x...... ,看來還是我的數(shù)據(jù)轉換的不對嘹吨,再看一眼調試頁面搬味。
C4 E3,貌似是十六進制數(shù)據(jù),%號什么鬼躺苦,它不可能轉成整型身腻,temp 一直是NaN,得 我去掉%號試試产还。
呀嘿匹厘,temp有值了,跟Android的數(shù)據(jù)差不多脐区,都是整數(shù)愈诚。過掉斷點看看。
哈哈,出來了炕柔,這一刻的心情你懂的酌泰。
到此 小程序藍牙打印算是流程搞通了,網(wǎng)上資料有時候不太全匕累,有時還有錯誤陵刹,這就需要我們大膽猜測勇敢驗證,最后福利來了欢嘿,我把完整demo貢獻上衰琐。
https://github.com/lerpo/bluethooth.git