这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

说明

基于uni-app开发,调用官方蓝牙相关api实现连接蓝牙与向蓝牙热敏打印机发送字节流,可打印文字,二维码,图片,调整字体大小等,本文提供大概思路

结构

  • bluetooth.js 蓝牙连接相关模块封装
  • commands.js 打印十六进制相关代码库
  • gbk.js 编码转换库地址
  • printerjobs.js 打印实现库

bluetooth.js

蓝牙连接相关封装代码

class Bluetooth {constructor() {this.isOpenBle = false;this.deviceId = "";this.serviceId = "";this.writeId = "";this.notifyId = "";this.BluetoothConnectStatus = false this.printStatus = false this.init()}init() {this.closeBluetoothAdapter().then(() = >{console.log("init初始关闭蓝牙模块") this.openBluetoothAdapter().then(() = >{console.log("init初始化蓝牙模块") this.reconnect() //自动连接蓝牙设备})})}showToast(title) {uni.showToast({title: title,icon: 'none','duration': 2000});}openBluetoothAdapter() {return new Promise((resolve, reject) = >{uni.openBluetoothAdapter({success: res = >{this.isOpenBle = true;resolve(res);},fail: err = >{this.showToast(`蓝牙未打开`);reject(err);},});});}startBluetoothDevicesDiscovery() {if (!this.isOpenBle) {this.showToast(`初始化蓝牙模块失败`) return;}let self = this;uni.showLoading({title: '蓝牙搜索中'}) return new Promise((resolve, reject) = >{setTimeout(() = >{uni.startBluetoothDevicesDiscovery({success: res = >{resolve(res)},fail: res = >{self.showToast(`搜索设备失败` + JSON.stringify(err));reject(err);}})},300);});}stopBluetoothDevicesDiscovery() {let self = this;return new Promise((resolve, reject) = >{uni.stopBluetoothDevicesDiscovery({success: e = >{uni.hideLoading();},fail: e = >{uni.hideLoading();self.showToast(`停止搜索蓝牙设备失败` + JSON.stringify(err));}})});}createBLEConnection() {//设备deviceIdlet deviceId = this.deviceId;let self = this;// uni.showLoading({//    mask: true,//   title: '设别连接中,请稍候...'// })console.log(this.deviceId);return new Promise((resolve, reject) = >{uni.createBLEConnection({deviceId,success: (res) = >{console.log("res:createBLEConnection " + JSON.stringify(res));resolve(res)},fail: err = >{uni.hideLoading();self.showToast(`停止搜索蓝牙设备失败` + JSON.stringify(err));reject(err);}})});}//获取蓝牙设备所有服务(service)getBLEDeviceServices() {let _serviceList = [];let deviceId = this.deviceId;let self = this;return new Promise((resolve, reject) = >{setTimeout(() = >{uni.getBLEDeviceServices({deviceId,success: res = >{for (let service of res.services) {if (service.isPrimary) {_serviceList.push(service);}}uni.hideLoading();console.log("_serviceList: " + JSON.stringify(_serviceList));resolve(_serviceList)},fail: err = >{uni.hideLoading();// self.showToast(`获取设备Services` + JSON.stringify(err));reject(err);},})},500);});}//获取蓝牙设备某个服务中所有特征值(characteristic)getBLEDeviceCharacteristics() {// console.log("getBLEDeviceCharacteristics")let deviceId = this.deviceId;let serviceId = this.serviceId;let self = this;return new Promise((resolve, reject) = >{uni.getBLEDeviceCharacteristics({deviceId,serviceId,success: res = >{for (let _obj of res.characteristics) {//获取notifyif (_obj.properties.notify) {self.notifyId = _obj.uuid;uni.setStorageSync('notifyId', self.notifyId);}//获取writeIdif (_obj.properties.write) {self.writeId = _obj.uuid;uni.setStorageSync('writeId', self.writeId);}}//console.log("res:getBLEDeviceCharacteristics " + JSON.stringify(res));let result = {'notifyId': self.notifyId,'writeId': self.writeId};// self.showToast(`获取服务中所有特征值OK,${JSON.stringify(result)}`);this.BluetoothStatus = true resolve(result)},fail: err = >{self.showToast(`getBLEDeviceCharacteristics` + JSON.stringify(err));reject(err);}})});}//断开联链接closeBLEConnection() {let deviceId = this.deviceId;uni.closeBLEConnection({deviceId,success(res) {console.log("closeBLEConnection" + res)}})}notifyBLECharacteristicValue() {let deviceId = this.deviceId;let serviceId = this.serviceId;let characteristicId = this.notifyId;uni.notifyBLECharacteristicValueChange({state: true,// 启用 notify 功能deviceId,serviceId,characteristicId,success(res) {uni.onBLECharacteristicValueChange(function(res) {console.log('onBLECharacteristicValueChange', res);});},fail(res) {console.log('notifyBLECharacteristicValueChange failed:' + res.errMsg);}});}writeBLECharacteristicValue(buffer) {let deviceId = this.deviceId;let serviceId = this.serviceId;let characteristicId = this.writeId;// console.log(deviceId);// console.log(serviceId);// console.log(characteristicId);return new Promise((resolve, reject) = >{uni.writeBLECharacteristicValue({deviceId,serviceId,characteristicId,value: buffer,success(res) {// console.log('message发送成功', JSON.stringify(res));resolve(res);},fail(err) {// console.log('message发送失败', JSON.stringify(err));reject(err);}});});}closeBluetoothAdapter() {return new Promise((resolve, reject) = >{uni.closeBluetoothAdapter({success: res = >{resolve()}});})}//若APP在之前已有搜索过某个蓝牙设备,并成功建立连接,可直接传入之前搜索获取的 deviceId 直接尝试连接该设备,无需进行搜索操作。reconnect() { (async() = >{try {this.deviceId = this.deviceId || uni.getStorageSync("deviceId");this.serviceId = this.serviceId || uni.getStorageSync("serviceId");console.log("this.deviceId", this.deviceId) console.log("this.serviceId", this.serviceId) let result1 = await this.createBLEConnection();console.log("createBLEConnection: " + JSON.stringify(result1));let result2 = await this.getBLEDeviceServices();console.log("getBLEDeviceServices: " + JSON.stringify(result2));let result3 = await this.getBLEDeviceCharacteristics();console.log("getBLEDeviceCharacteristics: " + JSON.stringify(result3));this.BluetoothConnectStatus = true this.showToast("蓝牙打印设备连接成功")// this.writeId = uni.getStorageSync("writeId");// this.notifyId = uni.getStorageSync("notifyId");} catch(err) {console.log("err: " + err);// this.showToast("蓝牙打印设备连接失败")}})();}
}export
default Bluetooth;

commands.js

打印机ESC/POS十六进制编码库

/*** 修改自https://github.com/song940/node-escpos/blob/master/commands.js* ESC/POS _ (Constants)*/
var _ = {LF: [0x0a],FS: [0x1c],FF: [0x0c],GS: [0x1d],DLE: [0x10],EOT: [0x04],NUL: [0x00],ESC: [0x1b],EOL: '\n',
};/*** [FEED_CONTROL_SEQUENCES Feed control sequences]* @type {Object}*/
_.FEED_CONTROL_SEQUENCES = {CTL_LF: [0x0a],   // Print and line feedCTL_GLF: [0x4a, 0x00],   // Print and feed paper (without spaces between lines)CTL_FF: [0x0c],   // Form feedCTL_CR: [0x0d],   // Carriage returnCTL_HT: [0x09],   // Horizontal tabCTL_VT: [0x0b],   // Vertical tab
};_.CHARACTER_SPACING = {CS_DEFAULT: [0x1b, 0x20, 0x00],CS_SET: [0x1b, 0x20]
};_.LINE_SPACING = {LS_DEFAULT: [0x1b, 0x32],LS_SET: [0x1b, 0x33]
};/*** [HARDWARE Printer hardware]* @type {Object}*/
_.HARDWARE = {HW_INIT: [0x1b, 0x40], // Clear data in buffer and reset modesHW_SELECT: [0x1b, 0x3d, 0x01], // Printer selectHW_RESET: [0x1b, 0x3f, 0x0a, 0x00], // Reset printer hardwarePrint:[0x1b, 0x64,0x01] //Print and feed paper
};/*** [CASH_DRAWER Cash Drawer]* @type {Object}*/
_.CASH_DRAWER = {CD_KICK_2: [0x1b, 0x70, 0x00], // Sends a pulse to pin 2 []CD_KICK_5: [0x1b, 0x70, 0x01], // Sends a pulse to pin 5 []
};/*** [MARGINS Margins sizes]* @type {Object}*/
_.MARGINS = {BOTTOM: [0x1b, 0x4f], // Fix bottom sizeLEFT: [0x1b, 0x6c], // Fix left sizeRIGHT: [0x1b, 0x51], // Fix right size
};/*** [PAPER Paper]* @type {Object}*/
_.PAPER = {PAPER_FULL_CUT: [0x1d, 0x56, 0x00], // Full cut paperPAPER_PART_CUT: [0x1d, 0x56, 0x01], // Partial cut paperPAPER_CUT_A: [0x1d, 0x56, 0x41], // Partial cut paperPAPER_CUT_B: [0x1d, 0x56, 0x42], // Partial cut paper
};/*** [TEXT_FORMAT Text format]* @type {Object}*/
_.TEXT_FORMAT = {TXT_NORMAL: [0x1b, 0x21, 0x00], // Normal textTXT_2HEIGHT: [0x1b, 0x21, 0x10], // Double height textTXT_2WIDTH: [0x1b, 0x21, 0x20], // Double width textTXT_4SQUARE: [0x1b, 0x21, 0x30], // Double width & height textTXT_UNDERL_OFF: [0x1b, 0x2d, 0x00], // Underline font OFFTXT_UNDERL_ON: [0x1b, 0x2d, 0x01], // Underline font 1-dot ONTXT_UNDERL2_ON: [0x1b, 0x2d, 0x02], // Underline font 2-dot ONTXT_BOLD_OFF: [0x1b, 0x45, 0x00], // Bold font OFFTXT_BOLD_ON: [0x1b, 0x45, 0x01], // Bold font ONTXT_ITALIC_OFF: [0x1b, 0x35], // Italic font ONTXT_ITALIC_ON: [0x1b, 0x34], // Italic font ONTXT_FONT_A: [0x1b, 0x4d, 0x00], // Font type ATXT_FONT_B: [0x1b, 0x4d, 0x01], // Font type BTXT_FONT_C: [0x1b, 0x4d, 0x02], // Font type CTXT_ALIGN_LT: [0x1b, 0x61, 0x00], // Left justificationTXT_ALIGN_CT: [0x1b, 0x61, 0x01], // CenteringTXT_ALIGN_RT: [0x1b, 0x61, 0x02], // Right justification
};/*** [BARCODE_FORMAT Barcode format]* @type {Object}*/
_.BARCODE_FORMAT = {BARCODE_TXT_OFF: [0x1d, 0x48, 0x00], // HRI barcode chars OFFBARCODE_TXT_ABV: [0x1d, 0x48, 0x01], // HRI barcode chars aboveBARCODE_TXT_BLW: [0x1d, 0x48, 0x02], // HRI barcode chars belowBARCODE_TXT_BTH: [0x1d, 0x48, 0x03], // HRI barcode chars both above and belowBARCODE_FONT_A: [0x1d, 0x66, 0x00], // Font type A for HRI barcode charsBARCODE_FONT_B: [0x1d, 0x66, 0x01], // Font type B for HRI barcode charsBARCODE_HEIGHT: function (height) { // Barcode Height [1-255]return [0x1d, 0x68, height];},BARCODE_WIDTH: function (width) {   // Barcode Width  [2-6]return [0x1d, 0x77, width];},BARCODE_HEIGHT_DEFAULT: [0x1d, 0x68, 0x64], // Barcode height default:100BARCODE_WIDTH_DEFAULT: [0x1d, 0x77, 0x01], // Barcode width default:1BARCODE_UPC_A: [0x1d, 0x6b, 0x00], // Barcode type UPC-ABARCODE_UPC_E: [0x1d, 0x6b, 0x01], // Barcode type UPC-EBARCODE_EAN13: [0x1d, 0x6b, 0x02], // Barcode type EAN13BARCODE_EAN8: [0x1d, 0x6b, 0x03], // Barcode type EAN8BARCODE_CODE39: [0x1d, 0x6b, 0x04], // Barcode type CODE39BARCODE_ITF: [0x1d, 0x6b, 0x05], // Barcode type ITFBARCODE_NW7: [0x1d, 0x6b, 0x06], // Barcode type NW7BARCODE_CODE93: [0x1d, 0x6b, 0x48], // Barcode type CODE93BARCODE_CODE128: [0x1d, 0x6b, 0x49], // Barcode type CODE128
};/*** [IMAGE_FORMAT Image format]* @type {Object}*/
_.IMAGE_FORMAT = {S_RASTER_N: [0x1d, 0x76, 0x30, 0x00], // Set raster image normal sizeS_RASTER_2W: [0x1d, 0x76, 0x30, 0x01], // Set raster image double widthS_RASTER_2H: [0x1d, 0x76, 0x30, 0x02], // Set raster image double heightS_RASTER_Q: [0x1d, 0x76, 0x30, 0x03], // Set raster image quadruple
};/*** [BITMAP_FORMAT description]* @type {Object}*/
_.BITMAP_FORMAT = {BITMAP_S8: [0x1b, 0x2a, 0x00],BITMAP_D8: [0x1b, 0x2a, 0x01],BITMAP_S24: [0x1b, 0x2a, 0x20],BITMAP_D24: [0x1b, 0x2a, 0x21]
};/*** [GSV0_FORMAT description]* @type {Object}*/
_.GSV0_FORMAT = {GSV0_NORMAL: [0x1d, 0x76, 0x30, 0x00],GSV0_DW: [0x1d, 0x76, 0x30, 0x01],GSV0_DH: [0x1d, 0x76, 0x30, 0x02],GSV0_DWDH: [0x1d, 0x76, 0x30, 0x03]
};/*** [BEEP description]* @type {string}*/
_.BEEP = [0x1b, 0x42]; // Printer Buzzer pre hex/*** [COLOR description]* @type {Object}*/_.COLOR = {0: [0x1b, 0x72, 0x00], // black1: [0x1b, 0x72, 0x01] // red
};/*** [exports description]* @type {[type]}*/
module.exports = _;

printerjobs.js

const commands = require('./commands');
const gbk = require('./gbk');const printerJobs = function() {this._queue = Array.from(commands.HARDWARE.HW_INIT);this._enqueue = function(cmd) {this._queue.push.apply(this._queue, cmd);}
};/*** 增加打印内容* @param  {string} content  文字内容*/
printerJobs.prototype.text = function(content) {if (content) {let uint8Array = gbk.encode(content);let encoded = Array.from(uint8Array);this._enqueue(encoded);}return this;
};/*** 打印文字* @param  {string} content  文字内容*/
printerJobs.prototype.print = function(content) {this.text(content);// this._enqueue(commands.LF);return this;
};
printerJobs.prototype.printL = function(content) {this.text(content);this._enqueue(commands.LF);return this;
};printerJobs.prototype.printImage = function(content) {if (content) {const cmds = [].concat([29, 118, 48, 0], content);// console.log("cmds",cmds)this._enqueue(cmds);this._enqueue(commands.LF);}return this;
};/*** 打印文字并换行* @param  {string}  content  文字内容*/
printerJobs.prototype.println = function(content = '') {return this.print(content + commands.EOL);
};/*** 设置对齐方式* @param {string} align 对齐方式 LT/CT/RT*/
printerJobs.prototype.setAlign = function(align) {this._enqueue(commands.TEXT_FORMAT['TXT_ALIGN_' + align.toUpperCase()]);return this;
};/*** 设置字体* @param  {string} family A/B/C*/
printerJobs.prototype.setFont = function(family) {this._enqueue(commands.TEXT_FORMAT['TXT_FONT_' + family.toUpperCase()]);return this;
};/*** 设定字体尺寸* @param  {number} width 字体宽度 1~2* @param  {number} height 字体高度 1~2*/
printerJobs.prototype.setSize = function(width, height) {if (2 >= width && 2 >= height) {this._enqueue(commands.TEXT_FORMAT.TXT_NORMAL);if (2 === width && 2 === height) {this._enqueue(commands.TEXT_FORMAT.TXT_4SQUARE);} else if (1 === width && 2 === height) {this._enqueue(commands.TEXT_FORMAT.TXT_2HEIGHT);} else if (2 === width && 1 === height) {this._enqueue(commands.TEXT_FORMAT.TXT_2WIDTH);}}return this;
};/*** 设定字体是否加粗* @param  {boolean} bold*/
printerJobs.prototype.setBold = function(bold) {if (typeof bold !== 'boolean') {bold = true;}this._enqueue(bold ? commands.TEXT_FORMAT.TXT_BOLD_ON : commands.TEXT_FORMAT.TXT_BOLD_OFF);return this;
};/*** 设定是否开启下划线* @param  {boolean} underline*/
printerJobs.prototype.setUnderline = function(underline) {if (typeof underline !== 'boolean') {underline = true;}this._enqueue(underline ? commands.TEXT_FORMAT.TXT_UNDERL_ON : commands.TEXT_FORMAT.TXT_UNDERL_OFF);return this;
};/*** 设置行间距为 n 点行,默认值行间距是 30 点* @param {number} n 0≤n≤255*/
printerJobs.prototype.setLineSpacing = function(n) {if (n === undefined || n === null) {this._enqueue(commands.LINE_SPACING.LS_DEFAULT);} else {this._enqueue(commands.LINE_SPACING.LS_SET);this._enqueue([n]);}return this;
};/*** 打印空行* @param {number} n*/
printerJobs.prototype.lineFeed = function(n = 1) {return this.print(new Array(n).fill(commands.EOL).join(''));
};/***  设置字体颜色,需要打印机支持*  @param  {number} color - 0 默认颜色黑色 1 红色*/
printerJobs.prototype.setColor = function(color) {this._enqueue(commands.COLOR[color === 1 ? 1 : 0]);return this;
};/*** https://support.loyverse.com/hardware/printers/use-the-beeper-in-a-escpos-printers* 蜂鸣警报,需要打印机支持* @param  {number} n    蜂鸣次数,1-9* @param  {number} t 蜂鸣长短,1-9*/
printerJobs.prototype.beep = function(n, t) {this._enqueue(commands.BEEP);this._enqueue([n, t]);return this;
};/*** 清空任务*/
printerJobs.prototype.clear = function() {this._queue = Array.from(commands.HARDWARE.HW_RESET);// this._enqueue(commands.HARDWARE.Print);return this;
};/*** 返回ArrayBuffer*/
printerJobs.prototype.buffer = function() {return new Uint8Array(this._queue).buffer;
};module.exports = printerJobs;

代码实现

封装蓝牙连接,搜索,断开相关操作模块

蓝牙搜索

startBluetoothDeviceDiscovery() {let self = this;self.tempDeviceList = [];uni.startBluetoothDevicesDiscovery({success: res = >{uni.onBluetoothDeviceFound(devices = >{// console.log("发现设备: " + JSON.stringify(devices));if (!self.tempDeviceList.some(item = >{return item.deviceId === devices.devices[0].deviceId || item.name === devices.devices[0].name})) {// console.log("new", devices.devices)self.tempDeviceList.push(devices.devices[0])}});this.connect = false this.$refs.popup.open()},fail: err = >{uni.showToast({title: '搜索设备失败' + JSON.stringify(err),icon: 'none'})}})
},

搜索完成选择设备

async select_deviceId(item) {this.deviceId = item.deviceId;this.$bluetooth.deviceId = item.deviceId;uni.setStorageSync('deviceId', this.$bluetooth.deviceId);this.serviceList = [];try {//1.链接设备let result = await this.$bluetooth.createBLEConnection();//2.寻找服务let result2 = null setTimeout(async() = >{result2 = await this.$bluetooth.getBLEDeviceServices();console.log("获取服务: " + JSON.stringify(result2));this.serviceList = result2;console.log("serviceList", this.serviceList.length)if (this.serviceList[2].uuid) {this.select_service(this.serviceList[2].uuid)} else {uni.showToast({title: '不是打印设备',icon: 'none'})}},1000)} catch(e) {//TODO handle the exceptionconsole.log("e: " + JSON.stringify(e));}
},

选中服务

async select_service(res) {console.log("select_service", res)this.$bluetooth.serviceId = res;console.log("this.$bluetooth.serviceId", this.$bluetooth.serviceId) uni.setStorageSync('serviceId', res);try {let result = await this.$bluetooth.getBLEDeviceCharacteristics();console.log("resultresult", result) this.$refs.popup.close()uni.showToast({title: "连接成功"})// this.pickUpOnce()} catch(e) {//TODO handle the exceptionconsole.log("e: " + JSON.stringify(e));}
},

打印内容组合

async writeBLECharacteristicValueTongzhishu() {let Qrcode_res = await this.get_Qrcode()let sign = await this.getSign()console.log("sign")let printerJobs = new PrinterJobs()let p = printerJobs.setAlign('ct').setBold(true).printL("打印测试")let buffer = printerJobs.buffer();this.printbuffs(buffer);
},

打印内容组合

主要是实现打印编码推送循环,手机蓝牙可能出现编码发送失败情况,这个时候就是要循环保证每个字节准确推送

printbuffs(buffer, fun) {console.log("printbuffs", buffer.byteLength) const maxChunk = 8;let p = Promise.resolve();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);p = p.then(() = >{if (i == 0) {this.$bluetooth.printStatus = true this.$refs.loading.open();}if ((i + maxChunk) >= length) {console.log("printEnd")setTimeout(() = >{this.$bluetooth.printStatus = false this.$refs.loading.close();},1000)}return this.printbuff(subPackage)})}p = p.then(() = >{console.log("printEve") fun()})},
async printbuff(buffer) {while (true) {try {await this.$bluetooth.writeBLECharacteristicValue(buffer);break;} catch(e) {}}
},

本文转载于:

https://juejin.cn/post/7001752261722537991

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

记录--uni-app实现蓝牙打印小票相关推荐

  1. Android蓝牙打印小票,仿美团外卖小票打印

    这个一个Android蓝牙打印小票demo,类似美团外卖小票打印 自适应排版小票格式,一行两列和三列轻松搞定,文本长短不用愁 先看一下效果图: demo里主要是使用汉印打印机进行蓝牙小票打印,它还支持 ...

  2. vue热敏打印机_vue h5+app蓝牙打印小票

    参考网址: 链接蓝牙:https://blog.csdn.net/cxgasd/article/details/78208708 蓝牙打印机指令:https://www.jianshu.com/p/c ...

  3. uni-app实现蓝牙打印小票

    说明 基于uni-app开发,调用官方蓝牙相关api实现连接蓝牙与向蓝牙热敏打印机发送字节流,可打印文字,二维码,图片,调整字体大小等 结构 bluetooth.js 蓝牙连接相关模块封装 comma ...

  4. Android 蓝牙打印小票与WiFi打印小票两种打印方式的实现(带有图片和二维码)

    转载至: https://blog.csdn.net/u011056653/article/details/74308254 最近在做小票打印这块,项目需求是蓝牙和WiFi两种都要实现,开始做的时候也 ...

  5. 记录app通过蓝牙连接小票打印机的坑

    试了好几台5.0以下版本的测试机,发现可正常通过蓝牙连接打印机,我就以为大功告成了,结果测试的时候,在锤子手机上一打开app就崩溃了... 报错信息: IllegalArgumentException ...

  6. 混合 html5蓝牙打印小票怎么排版,蓝牙打印机打印小票项目版

    项目需要需要写一个手机开小票的东西,蓝牙打印机是目前比较成熟的东西!某宝买了一个蓝牙打印机和几卷热敏纸开搞..... 本人对android原生的东西不了解,也不想去麻烦我们的android工程师,只好 ...

  7. 记录uni.app开发微信小程序中地图的使用,以及项目中的解决办法

    标题先讲一下需求:需要获取用户的地址信息以及经纬度,并在地图中展示时出来 uniapp官方也提供了api uni.getLocation(OBJECT) getLocation只能获取用户的经纬度,不 ...

  8. 单据小票打印模板自定义设计,手机收银软件APP搭配蓝牙便携打印机,移动便携打印零售单单据小票

    单据小票打印模板自定义设计,手机收银软件APP搭配蓝牙便携打印机,移动便携打印零售单单据小票,轻松实现仓库条码管理,扫码入库出库盘点_哔哩哔哩_bilibili单据小票打印模板自定义设计,手机收银软件 ...

  9. WeX5 3.8开发工具之蓝牙打印(全流程记录不是最全,胜似最全)

    技术分享 记录踩过的坑和别的大佬没有叽歪的点 开始做蓝牙打印看到网上很多做混合开发 和安卓开发,ios开发的例子,插件等等版本大同小异,并不是像其他博客上所说的那么简单,[下载插件,无需改动,连接打印 ...

最新文章

  1. 如何最小化混合云中影子IT带来的风险
  2. 设计模式:结构型模式总结
  3. Excel的基础操作
  4. 谈谈苹果应用内支付(IAP)的坑
  5. 网页设计工资一般多少_初级会计师就业前景怎么样?工资一般多少?
  6. python基础代码大全-Python网络爬虫实战项目代码大全(长期更新,欢迎补充)
  7. 服务器安装cos系统,COS(国产操作系统)安装教程
  8. python中snip_Snip滚动截屏_腾讯Snip For Mac官方下载-华军软件园
  9. 13.0、veu-路由嵌套
  10. 计算机网络教程第五版|微课版 - 第一章 概述 - 重点概念
  11. C语言编程 判断某年某月有几天,C++自定义函数判断某年某月某日是这一年中第几天...
  12. Enterprise Architect 类关系对应解析
  13. 中标麒麟linux系统安装打印机_中标麒麟Linux操作系统和理光打印机完成互相兼容认证...
  14. 百家号怎么发送链接,发送自己的链接变成文字等解答
  15. 老男孩网络安全 | 从小白到月薪13k,仅仅只用了三个多月的时间!
  16. python中使用modbus_tk操作浮点数
  17. muduo源码剖析——Singleton单例模式之懒汉模式与DCL双重检查
  18. 将符号(amp; amp;)解码为正常
  19. c语言字符substr,c substr()字符函数的使用方法
  20. TK 设置tkinter窗口的置顶属性,保持最上层

热门文章

  1. 字符串的对比(python)
  2. 一个java程序员的真实经历
  3. Java---一周总结 4.2 争强时间管理,防止进入时间黑洞
  4. 域格4G网优模块获取
  5. 移动通信考前预习_第4章_全球移动系统(GSM)
  6. 买了套新概念英语,感觉不错
  7. 用Exchange 2000开发企业办公自动化系统
  8. 【C++】list的模拟实现+迭代器的设计思维
  9. 管家婆勒索病毒怎么处理?管家婆勒索病毒怎么办?管家婆勒索病毒怎么解决?
  10. 基于磁场定位的眼动追踪