Web實現藍牙打印及Webbluetooth的用法


在Web的項目中,前端界面往往會有一些打印功能,本身瀏覽器的打印功能也挺好用的,但是瀏覽器一般是輸出到普通A4打印機,如果需要打印一些便簽之類,需要用到藍牙打印機,這時這個打印功能就無能為力了。幸好我發現了一個Webbluetooth的項目,這個項目也是一個谷歌官方發起的項目,實現網頁對藍牙的調用,目前Chrome系較高版本瀏覽器支持。
要使用Web藍牙功能需要一個usb口的藍牙適配器,可以在Chrome瀏覽器中輸入"chrome://bluetooth-internals"查看藍牙設備狀態,該調試功能非常強大!
https://img2020.cnblogs.com/blog/2200166/202104/2200166-20210413173113337-178416286.png
通過UUID可以查看到所有的藍牙設備、service、Characteristics,以及讀寫藍牙設備
https://img2020.cnblogs.com/blog/2200166/202104/2200166-20210413173541465-1728731161.png
藍牙打印機連接上后不是發文本就能直接打印,而是要轉換成打印指令,一般是通過ESC/POS通用打印指令傳遞打印指令的,就是說我們要輸出的文本、二維碼、圖片等內容需要轉換成ESC/POS指令。目前大多數藍牙打印機都是支持ESC/POS指令的,指令可以看https://www.jianshu.com/p/dd6ca0054298 了解下,百度上還有專門詳盡的指令集說明,不過我們不需要自己來寫指令轉換代碼,我找到一個js庫,很方便的實現了ESC/POS編碼,https://www.npmjs.com/package/@freedom_sky/esc-pos-encoder
Webbluetooth如何應用,https://segmentfault.com/a/1190000018224699,這里有個文檔簡單說明。https://bluetooth.rocks/tweets/這個則是有案例,也可以把代碼扒下來,我將它改寫成一個模塊
`
class BluetoothPrinter {
constructor() {
this._EVENTS = {};
this._CHARACTERISTIC = null;
this._QUEUE = [];
this._WORKING = false;
}

connect() {
	console.log('Requesting Bluetooth Device...');
	
	return new Promise((resolve, reject) => {
	
		navigator.bluetooth.requestDevice({
			filters: [{ services: ['000018f0-0000-1000-8000-00805f9b34fb'] }]
		})
			.then(device => {
				console.log('Connecting to GATT Server...');

				device.addEventListener('gattserverdisconnected', this._disconnect.bind(this));
				return device.gatt.connect();
			})
			.then(server => server.getPrimaryService("000018f0-0000-1000-8000-00805f9b34fb"))
			.then(service => service.getCharacteristic("00002af1-0000-1000-8000-00805f9b34fb"))
			.then(characteristic => {
				this._CHARACTERISTIC = characteristic;
				resolve();
			})
			.catch(error => {
				console.log('Could not connect! ' + error);
				reject();
			});			
	});
	
}

print(command) {
	const maxLength = 100;
	let chunks = Math.ceil(command.length / maxLength);

	if (chunks === 1) {
		this._queue(command);
	} else {
		for (let i = 0; i < chunks; i++) {
			let byteOffset = i * maxLength;
			let length = Math.min(command.length, byteOffset + maxLength);
			this._queue(command.slice(byteOffset, length));
		}
	}
}

_queue(f) {
	var that = this;
	
	function run() {
		if (!that._QUEUE.length) {
			that._WORKING = false; 
			return;
		}
		
		that._WORKING = true;
		that._CHARACTERISTIC.writeValue(that._QUEUE.shift()).then(() => run() );
	}
	
	that._QUEUE.push(f);
	
	if (!that._WORKING) run();	
}

addEventListener(e, f) {
	this._EVENTS[e] = f;
}

isConnected() {
	return !! this._CHARACTERISTIC;
}
	
_disconnect() {
	console.log('Disconnected from GATT Server...');

	this._CHARACTERISTIC = null;
	
	if (this._EVENTS['disconnected']) {
		this._EVENTS['disconnected']();
	}
}

};

module.exports = BluetoothPrinter;
`
使用的時候直接require進來,在調用的過程中卻總是出錯
https://img2020.cnblogs.com/blog/2200166/202104/2200166-20210413173850577-1771718518.png
Could not connect! SecurityError: Failed to execute 'requestDevice' on 'Bluetooth': Must be handling a user gesture to show a permission request.
用必應查了一遍文章解決了這個問題https://web.dev/bluetooth/,原來出來安全性的考慮,一定需要用戶交互才能使用Web藍牙,就是說必須是通過點擊按鈕等用戶行為才能有權限打開藍牙,創建一個index.js

`let EscPosEncoder = require('esc-pos-encoder');
let BluetoothPrinter = require('./bluetooth-printer');

window.EscPosEncoder=new EscPosEncoder();
window.BluetoothPrinter = new BluetoothPrinter();
`

然后再創建index.html

`

` 用webpack打包運行,成功打印。

還有一個要注意的點,webbluetooth在本地可以直接調用,但部署上服務器一定需要HTTPS支持(其他硬件方面的web調用也同理),如果沒有的話會出現

查看HTTP和HTTPS下的naviagtor,HTTP下是沒有bluetooth等成員的


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM