如何使用小程序进行蓝牙打印
小程序蓝牙打印流程
需求全流程
- 初始化蓝牙模块,并搜索蓝牙打印机
- 选择蓝牙打印,并建立链接
- 获取蓝牙打印机服务,获取写入特征码
- 转换数据,向蓝牙打印机写入数据
代码细化
-
初始化蓝牙模块,并搜索蓝牙打印机
wx.openBluetoothAdapter({ success: (res) => { console.log('openBluetoothAdapter success', res) // 系统蓝牙模块打开。,并且蓝牙初始化成功后开始搜索蓝牙打印机 startBluetoothDevicesDiscovery() }, fail: (res) => { // 一般如果系统蓝牙模块启动失败,或者设备不支持蓝牙则会初始化失败 console.log('openBluetoothAdapter fail', res) if (res.errCode === 10001) { wx.showModal({ title: '错误', content: '蓝牙初始化失败, 请打开蓝牙后重试。', showCancel: false }) // 当蓝牙设备状态发生改变后,需要重新扫描蓝牙打印机列表 wx.onBluetoothAdapterStateChange((res) => { console.log('onBluetoothAdapterStateChange', res) if (res.available) { // 取消监听,否则stopBluetoothDevicesDiscovery后仍会继续触发 onBluetoothAdapterStateChange, // 导致再次调用startBluetoothDevicesDiscovery wx.onBluetoothAdapterStateChange(() => { }) startBluetoothDevicesDiscovery() } }) } } })
开始搜索蓝牙打印机
const startBluetoothDevicesDiscovery = () => { if (_discoveryStarted) { return } _discoveryStarted = true // 开始搜索蓝牙 wx.startBluetoothDevicesDiscovery({ success: (res) => { console.log('startBluetoothDevicesDiscovery success', res) // 搜索到蓝牙打印机后,会以事件回调的形式触发,需要注册事件 onBluetoothDeviceFound() }, fail: (res) => { console.log('startBluetoothDevicesDiscovery fail', res) } }) }
当蓝牙查找到
// 当蓝牙查找到 const onBluetoothDeviceFound = () => { wx.onBluetoothDeviceFound((res) => { res.devices.forEach(device => { // 排除非法命名的设备 if (!device.name && !device.localName) { return } const foundDevices = devices const idx = inArray(foundDevices, 'deviceId', device.deviceId) const data = {} if (idx === -1) { devices[foundDevices.length] = device } else { devices[idx] = device } devices = devices.map(item => { item.feild = item.name return item }) // 将其存入数据仓库,会在其他地方用到 store.commit('bluetooth/UPDATE_DEVICES', devices) console.log('devices', store.state.bluetooth.devices) }) }) }
-
选择蓝牙打印,并建立链接
const _createBLEConnection = (deviceId, name) => { wx.showLoading() wx.createBLEConnection({ deviceId, success: () => { console.log('createBLEConnection success') connected = true name = name deviceId = deviceId // 获取蓝牙服务和写入特征码 getBLEDeviceServices(deviceId) wx.setStorage({ key: LAST_CONNECTED_DEVICE, data: name + ':' + deviceId }) }, complete() { wx.hideLoading() }, fail: (res) => { console.log('createBLEConnection fail', res) wx.showModal({ title: '错误', content: '蓝牙连接失败', showCancel: false }) } }) // 建立连接后停止搜索蓝牙,搜索蓝牙还是挺耗性能的(费电) stopBluetoothDevicesDiscovery() }
-
获取蓝牙打印机服务,获取写入特征码
链接蓝牙后获取打印服务
wx.getBLEDeviceServices({ deviceId, success: (res) => { console.log('getBLEDeviceServices', res) for (let i = 0; i < res.services.length; i++) { if (res.services[i].isPrimary) { getBLEDeviceCharacteristics(deviceId, res.services[i].uuid) return } } } })
获取蓝牙打印机的所有打印服务后,从打印服务中获取打印特征码
wx.getBLEDeviceCharacteristics({ deviceId, serviceId, success: (res) => { console.log('getBLEDeviceCharacteristics success', res) // 这里会存在特征值是支持write,写入成功但是没有任何反应的情况 // 只能一个个去试 for (let i = 0; i < res.characteristics.length; i++) { const item = res.characteristics[i] if (item.properties.write) { canWrite = true _deviceId = deviceId _serviceId = serviceId _characteristicId = item.uuid console.log(_deviceId, _serviceId, _characteristicId) break } } }, fail(res) { console.error('getBLEDeviceCharacteristics', res) } })
打印的准备工作已完成,接下来就可以开始着手处理打印数据了
-
转换数据,向蓝牙打印机写入数据
使用 sfBluetoothPrint 进行转换打印数据,蓝牙打印机只能读取 ArrayBuffer
import HrPrint from '../sfBluetoothPrint/lib/index' const printObj = new HrPrint({ bytes: 200, // 传输速率,一般的低功耗蓝牙每秒只能传输 20 字节,蓝牙5.2设备提高传输阈值 })
执行打印
const writeBLECharacteristicValue = (str) => { const params = { wayBillData: str, // 打印数据(打印指令集的str数组) deviceId: _deviceId, // 设备id serviceId: _serviceId, // 打印id writeId: _characteristicId, // 写入特征码 } console.log(params) return printObj.print(params) }
printObj.print 方法实际上就是做了一个转换和断点续传
BluetoothPrint.prototype.writeBLECharacteristicValueUseArray = function writeBLECharacteristicValueUseArray(_ref5) { var wayBillData = _ref5.wayBillData; var deviceId = _ref5.deviceId; var serviceId = _ref5.serviceId; var writeId = _ref5.writeId; // 向蓝牙设备发送一个0x00的16进制数据 var _this = this; return new Promise(function (resolve, reject) { if (wayBillData.length > 0) { (function () { var item = wayBillData.shift(); var cpcl = item.content.replace(/\n/g, '\r\n'); var buffer = _utilsIndexJs.stringToBuffer2(cpcl); var bytes = buffer.byteLength; var bytesLength = _this.bytes; if (bytes > bytesLength) { var tmpBuffer = undefined; for (var y = 0; y < bytes; y += bytesLength) { tmpBuffer = buffer.slice(y, y + bytesLength); _this.writeToBLE({ tmpBuffer: tmpBuffer, byts: y, deviceId: deviceId, serviceId: serviceId, writeId: writeId }).then(function (res) { if (res >= bytes - bytesLength && wayBillData.length > 0) { _this.writeBLECharacteristicValueUseArray({ wayBillData: wayBillData, deviceId: deviceId, serviceId: serviceId, writeId: writeId }); } else { resolve(); } })['catch'](function (res) { reject(res); }); } } else { _this.writeToBLE({ tmpBuffer: buffer, byts: null, deviceId: deviceId, serviceId: serviceId, writeId: writeId }).then(function (res) { if (arr.length > 0) { _this.writeBLECharacteristicValueUseArray({ wayBillData: wayBillData, deviceId: deviceId, serviceId: serviceId, writeId: writeId }); } else { resolve(); } })['catch'](function (res) { reject(res); }); } })(); } }); };
打印指令集转码
var stringToBuffer2 = function stringToBuffer2(str) { var buffer = new ArrayBuffer(sumStrLength(str) * 4); var 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]); // gbk.js 详见 http://www.vuln.cn/2901 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); //var temp = strToHexCharCode(code); dataView.setUint8(p++, temp); } } else { var temp = data.charCodeAt(i); dataView.setUint8(p++, temp); } } return buffer; };
以下是完整代码
import store from '@/store'
import HrPrint from '../sfBluetoothPrint/lib/index'
// 解决断开提示多次触发的问题
let onece = false
const printObj = new HrPrint({
bytes: 200,
})
let _discoveryStarted = false
let devices = []
let connected = false
let chs = []
let name = null
let deviceId = null
let canWrite = false
let _characteristicId = null
let _serviceId = null
let _deviceId = null
const LAST_CONNECTED_DEVICE = 'last_connected_device'
const inArray = (arr, key, val) => {
for (let i = 0; i < arr.length; i++) {
if (arr[i][key] === val) {
return i
}
}
return -1
}
//将字符串转换成ArrayBufer
function string2buffer(str) {
if (!str) return
var val = ''
for (var i = 0; i < str.length; i++) {
val += str.charCodeAt(i).toString(16)
}
str = val
val = ''
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
}
// 初始化蓝牙
const init = () => {
wx.openBluetoothAdapter({
success: (res) => {
console.log('openBluetoothAdapter success', res)
startBluetoothDevicesDiscovery()
},
fail: (res) => {
console.log('openBluetoothAdapter fail', res)
if (res.errCode === 10001) {
wx.showModal({
title: '错误',
content: '蓝牙初始化失败, 请打开蓝牙后重试。',
showCancel: false
})
wx.onBluetoothAdapterStateChange((res) => {
console.log('onBluetoothAdapterStateChange', res)
if (res.available) {
// 取消监听,否则stopBluetoothDevicesDiscovery后仍会继续触发onBluetoothAdapterStateChange,
// 导致再次调用startBluetoothDevicesDiscovery
wx.onBluetoothAdapterStateChange(() => { })
startBluetoothDevicesDiscovery()
}
})
}
}
})
wx.onBLEConnectionStateChange((res) => {
// 该方法回调中可以用于处理连接意外断开等异常情况
console.log('onBLEConnectionStateChange',
`device ${res.deviceId} state has changed, connected: ${res.connected}`)
connected = res.connected
if (!res.connected && !onece) {
wx.showModal({
title: '错误',
content: '蓝牙连接已断开',
showCancel: false
})
onece = true
}
if (res.connected) {
onece = false
}
})
wx.onBLECharacteristicValueChange((res) => {
console.log('onBLECharacteristicValueChange', res)
})
}
// 查找蓝牙
const startBluetoothDevicesDiscovery = () => {
if (_discoveryStarted) {
return
}
_discoveryStarted = true
wx.startBluetoothDevicesDiscovery({
success: (res) => {
console.log('startBluetoothDevicesDiscovery success', res)
onBluetoothDeviceFound()
},
fail: (res) => {
console.log('startBluetoothDevicesDiscovery fail', res)
}
})
}
// 停止查找蓝牙
const stopBluetoothDevicesDiscovery = () => {
wx.stopBluetoothDevicesDiscovery({
complete: () => {
console.log('stopBluetoothDevicesDiscovery')
_discoveryStarted = false
}
})
}
// 获取蓝牙查找状态
const getBluetoothAdapterState = () => {
wx.getBluetoothAdapterState({
success: (res) => {
console.log('getBluetoothAdapterState', res)
if (res.discovering) {
onBluetoothDeviceFound()
} else if (res.available) {
startBluetoothDevicesDiscovery()
}
}
})
}
// 当蓝牙查找到
const onBluetoothDeviceFound = () => {
wx.onBluetoothDeviceFound((res) => {
res.devices.forEach(device => {
if (!device.name && !device.localName) {
return
}
const foundDevices = devices
const idx = inArray(foundDevices, 'deviceId', device.deviceId)
const data = {}
if (idx === -1) {
devices[foundDevices.length] = device
} else {
devices[idx] = device
}
devices = devices.map(item => {
item.feild = item.name
return item
})
store.commit('bluetooth/UPDATE_DEVICES', devices)
console.log('devices', store.state.bluetooth.devices)
})
})
}
// 建立蓝牙连接
const createBLEConnection = (target) => {
const deviceId = target.deviceId
const name = target.name
_createBLEConnection(deviceId, name)
}
const _createBLEConnection = (deviceId, name) => {
wx.showLoading()
wx.createBLEConnection({
deviceId,
success: () => {
console.log('createBLEConnection success')
connected = true
name = name
deviceId = deviceId
getBLEDeviceServices(deviceId)
wx.setStorage({
key: LAST_CONNECTED_DEVICE,
data: name + ':' + deviceId
})
},
complete() {
wx.hideLoading()
},
fail: (res) => {
console.log('createBLEConnection fail', res)
wx.showModal({
title: '错误',
content: '蓝牙连接失败',
showCancel: false
})
}
})
stopBluetoothDevicesDiscovery()
}
// 关闭蓝牙连接
const closeBLEConnection = () => {
wx.closeBLEConnection({
deviceId
})
connected = false
chs = []
canWrite = false
}
// 获取蓝牙服务
const getBLEDeviceServices = (deviceId) => {
wx.getBLEDeviceServices({
deviceId,
success: (res) => {
console.log('getBLEDeviceServices', res)
for (let i = 0; i < res.services.length; i++) {
if (res.services[i].isPrimary) {
getBLEDeviceCharacteristics(deviceId, res.services[i].uuid)
return
}
}
}
})
}
// 所有服务中的所有特征值
const getBLEDeviceCharacteristics = (deviceId, serviceId) => {
wx.getBLEDeviceCharacteristics({
deviceId,
serviceId,
success: (res) => {
console.log('getBLEDeviceCharacteristics success', res)
// 这里会存在特征值是支持write,写入成功但是没有任何反应的情况
// 只能一个个去试
for (let i = 0; i < res.characteristics.length; i++) {
const item = res.characteristics[i]
if (item.properties.write) {
canWrite = true
_deviceId = deviceId
_serviceId = serviceId
_characteristicId = item.uuid
console.log(_deviceId, _serviceId, _characteristicId)
break
}
}
},
fail(res) {
console.error('getBLEDeviceCharacteristics', res)
}
})
}
// 关闭蓝牙模块
const closeBluetoothAdapter = () => {
wx.closeBluetoothAdapter()
_discoveryStarted = false
}
// 快速连接
const createBLEConnectionWithDeviceId = (e) => {
const lastDevice = wx.getStorageSync(LAST_CONNECTED_DEVICE)
// 小程序在之前已有搜索过某个蓝牙设备,并成功建立连接,可直接传入之前搜索获取的 deviceId 直接尝试连接该设备
const device = lastDevice
if (!device) {
return
}
const index = device.indexOf(':')
const name = device.substring(0, index)
const deviceId = device.substring(index + 1, device.length)
console.log('createBLEConnectionWithDeviceId', name + ':' + deviceId)
wx.openBluetoothAdapter({
success: (res) => {
console.log('openBluetoothAdapter success', res)
_createBLEConnection(deviceId, name)
},
fail: (res) => {
console.log('openBluetoothAdapter fail', res)
if (res.errCode === 10001) {
wx.showModal({
title: '错误',
content: '未找到蓝牙设备, 请打开蓝牙后重试。',
showCancel: false
})
wx.onBluetoothAdapterStateChange((res) => {
console.log('onBluetoothAdapterStateChange', res)
if (res.available) {
// 取消监听
wx.onBluetoothAdapterStateChange(() => { })
_createBLEConnection(deviceId, name)
}
})
}
}
})
}
// 执行打印
const writeBLECharacteristicValue = (str) => {
const params = {
wayBillData: str,
deviceId: _deviceId,
serviceId: _serviceId,
writeId: _characteristicId,
}
console.log(params)
return printObj.print(params)
}
export {
init,
closeBluetoothAdapter,
closeBLEConnection,
createBLEConnection,
stopBluetoothDevicesDiscovery,
writeBLECharacteristicValue
}
转载自:https://juejin.cn/post/7210949519407644727