基于Native.js 實作的連接配接藍牙列印機
-
- 列印效果圖
- 核心代碼
- 測試代碼
- 運作裝置及環境
- PS:
- PPS:
- Demo
列印效果圖

核心代碼
/**
* @Description: 藍牙列印類 基于h5+ Native.js
* @Author: EricLee
* @Date: 2020-10-14 13:53:23
* @Param: mod
* @Return: $
*/
export const Bluetooth = function () {
// 全局 變量
let main = null,
BluetoothAdapter = null,
UUID = null,
uuid = null,
BAdapter = null,
device = null,
bluetoothSocket = null,
outputStream = null,
OutputStreamWriter = null,
writer = null
this.status = 0 // 和裝置的連接配接狀态: 0 未連接配接 1 連接配接中 2 已連接配接 (可以列印) 注: ** 此狀态不是 手機藍牙和裝置的配對狀态 **
// 初始化
this.initState = function () {
main = plus.android.runtimeMainActivity()
BluetoothAdapter = plus.android.importClass('android.bluetooth.BluetoothAdapter')
BAdapter = BluetoothAdapter.getDefaultAdapter()
UUID = plus.android.importClass('java.util.UUID')
uuid = UUID.fromString('00001101-0000-1000-8000-00805F9B34FB')
this.status = 1
this.queryBindDevice()
}
// 擷取配對裝置 mac位址
this.queryBindDevice = function () {
var lists = BAdapter.getBondedDevices()
plus.android.importClass(lists)
// var resultDiv = document.getElementById('bluetooth_list')
var iterator = lists.iterator()
plus.android.importClass(iterator)
console.log('==> 裝置清單長度', lists.size())
if (lists.size() == 0) {
mui.toast('連接配接失敗!未檢測到已配對成功的裝置!')
return
}
if (lists.size() > 1) {
mui.toast('連接配接失敗!檢測到多個配對成功裝置!')
return
}
while (iterator.hasNext()) {
var d = iterator.next()
plus.android.importClass(d)
console.log(d.getAddress())
console.log(d.getName())
this.createConnect(d.getAddress()) // 建立連接配接
}
}
// 建立連接配接
this.createConnect = function (mac) {
if (!mac) {
mui.toast('連接配接失敗!未能擷取裝置MAC位址!')
this.status = 0
return
}
device = BAdapter.getRemoteDevice(mac) // 連接配接列印機
plus.android.importClass(device)
// 隻需建立一次連接配接,多次調用不能正常列印 !!!
bluetoothSocket = device.createInsecureRfcommSocketToServiceRecord(uuid)
plus.android.importClass(bluetoothSocket)
if (!bluetoothSocket.isConnected()) {
console.log('斷開了,需要重新連接配接,連接配接中')
bluetoothSocket.connect()
}
mui.toast('列印機已準備就緒,可以列印!')
this.status = 2
// 注冊列印類
outputStream = bluetoothSocket.getOutputStream()
plus.android.importClass(outputStream)
OutputStreamWriter = plus.android.importClass('java.io.OutputStreamWriter')
writer = new OutputStreamWriter(outputStream, 'GBK')
plus.android.importClass(writer)
}
// 關閉IO 關閉連接配接
// 關閉頁面時必需調用該方法,要不下次不能正常連接配接裝置 !!!
this.closeConnect = function () {
bluetoothSocket.close()
outputStream.close()
OutputStreamWriter.close()
bluetoothSocket = null
outputStream = null
OutputStreamWriter = null
device = null
this.status = 0
}
// 走紙 n = 點行數
this.feedPoint = function (n) {
const point = n || 8
writer.write(0x1B)
writer.write(0x4A)
writer.write(point) // 點行 8 點 = 1mm
writer.flush()
}
// 走紙 n = 行數
this.feedLine = function (n) {
const line = n || 1
writer.write(0x1B)
writer.write(0x64)
writer.write(line) // 行數
writer.flush()
}
// 設定左邊距
this.setLeftMargin = function (n, m) {
writer.write(0x1D)
writer.write(0x4C)
writer.write(n) // 行數
writer.write(m) // 行數
writer.flush()
}
// 列印空行 linNum 行數
this.printLine = function (lineNum) {
for (let i = 0; i < lineNum; i++) {
writer.write('\n')
}
writer.flush()
}
// 設定列印 位置 // 0 右 1 中 2 右
this.setPrintPosition = function (n) {
let m = n || 1
writer.write(0x1B)
writer.write(0x61)
writer.write(m) // 0 右 1 中 2 右
writer.flush()
}
// 設定絕對列印位置
this.setPrintLocation = function (light, weight) {
writer.write(0x1B)
writer.write(0x24)
writer.write(light) // 0≤ light ≤ 255
writer.write(weight) // 0≤ weight ≤ 2
writer.flush()
}
// 列印空白(一個Tab的位置,約4個漢字)
this.printTabSpace = function (n) {
for (let i = 0; i < n; i++) {
writer.write('\t')
}
writer.flush()
}
// 設定/解除字元旋轉模式
// 0解除旋轉模式 1設定90°順時針旋轉模式 2設定180°順時針旋轉模式 3設定270°順時針旋轉模式
this.setPrintRotate = function (n) {
writer.write(0x1B)
writer.write(0x56)
writer.write(n)
writer.flush()
}
// 列印位圖 todo
this.printBitmap = function (m, data) {
writer.write(0x1B)
writer.write(0x2A)
writer.write(m)
writer.write(data)
}
// 字元縮放
this.setCharacterScale = function (n) {
// 列印倍寬高
if (n == 1) {
writer.write(0x1B)
writer.write(0x21)
writer.write(16)
writer.flush()
writer.write(0x1B)
writer.write(0x21)
writer.write(32)
writer.flush()
} else {
writer.write(0x1B)
writer.write(0x21)
writer.write(0)
writer.flush()
}
}
// 列印初始化 每次列印前必須調用!!!
this.initPrinter = function () {
writer.write(0x1B)
writer.write(0x40)
writer.flush()
}
// 列印文字 并換行
this.printTextNewLine = function (byteStr) {
if (!main) {
mui.toast('裝置未進行配對!')
return
}
var bytes = plus.android.invoke(byteStr, 'getBytes', 'gbk')
console.log(bytes)
outputStream.write(bytes)
outputStream.flush()
// 換行
writer.write('\n')
writer.flush()
console.log('print ')
}
// 列印字元串方法 byteStr 隻能是字元串
this.printText = function (byteStr, l, w) {
if (!main) {
mui.toast('裝置未進行配對!')
return
}
var bytes = plus.android.invoke(byteStr, 'getBytes', 'gbk')
console.log(bytes)
outputStream.write(bytes)
outputStream.flush()
console.log('print ')
// device = null
}
/**
* @Description: 二維碼列印
* @Author: EricLee
* @Date: 2020-10-15 15:16:10
* @Param: byteStr {String} 要列印的内容
* @Return: void
*/
this.printQrcode = function (byteStr) {
if (!main) {
mui.toast('裝置未進行配對!')
return
}
// init
var moduleSize = 8
var bytes = plus.android.invoke(byteStr, 'getBytes', 'gbk')
var length = bytes.length
console.log(length)
// 緩存二維碼資料
writer.write(0x1D)// init
writer.write('(k')// adjust height of barcode
writer.write(length + 3) // pl
writer.write(0) // ph
writer.write(49) // cn
writer.write(80) // fn
writer.write(48) //
writer.write(byteStr)
// 二維碼糾錯等級
writer.write(0x1D)
writer.write('(k')
writer.write(3)
writer.write(0)
writer.write(49)
writer.write(69)
writer.write(48)
// 設定二維碼塊大小
writer.write(0x1D)
writer.write('(k')
writer.write(3)
writer.write(0)
writer.write(49)
writer.write(67)
writer.write(moduleSize)
// 列印已緩存的資料二維碼
writer.write(0x1D)
writer.write('(k')
writer.write(3) // pl
writer.write(0) // ph
writer.write(49) // cn
writer.write(81) // fn
writer.write(48) // m
writer.flush()
// 二維碼列印 結束
console.log('print Qrcode')
}
}
測試代碼
<template>
<div>
<div>
<Button @click="_initBluetooth">{{ statusList[status] }}</Button>
</div>
<div>
<!-- <Button @click="_printText('DC:0D:30:9B:AC:99')">列印</Button>-->
<Button @click="_printTest(msg)">列印</Button>
<br/>
<Button @click="_printQrcode(code)">列印二維碼</Button>
</div>
<div>
<br/>
<Input v-model="line" placeholder="走紙行數" />
<Button @click="feed(line)">走紙</Button>
</div>
<div>
<br/>
<Input v-model="marginNum" placeholder="定位" />
<Button @click="_setPrintPosition(marginNum)">定位</Button>
</div>
<div>
<br/>
<Button @click="_setCharacterScale(1)">放大</Button>
<Button @click="_setCharacterScale(0)">縮小</Button>
</div>
<div>
<br/>
<Input v-model="light" placeholder="light" />
<Input v-model="weight" placeholder="weight" />
<Button @click="_setPrintLocation(light,weight)">絕對位置</Button>
</div>
<div>
<br/>
<Input v-model="rotateNum" placeholder="旋轉" />
<Button @click="_setPrintRotate(rotateNum)">旋轉</Button>
</div>
<div>
<br/>
<Button @click="_closeConnect()">關閉連接配接</Button>
</div>
</div>
</template>
<script>
import {Bluetooth} from '../lib/bluetooth'
export default {
name: 'printTest',
data () {
return {
msg: '樣品内容\n' + '101013Q73898\n' + '2020-10-10 09:33:33\n' + '張三三\n',
code: '191013Q7398',
mac: '',
line: 8,
light: 0,
weight: 0,
rotateNum: 0,
marginNum: 1,
initFlag: false,
bluetoothPrinter: null,
text: '配對',
status: 0,
statusList: [
'待連接配接',
'連接配接中',
'已連接配接'
]
}
},
mounted () {
this._initBluetooth()
},
destroyed () {
this._closeConnect()
},
watch: {
status () {
console.log('status==>', this.status)
if (this.status == 2) {
this._loading(false)
}
}
},
methods: {
_loading (flag) {
if (flag) {
this.$vux.loading.show({
text: 'Loading'
})
setTimeout(() => {
this.$vux.loading.hide()
}, 5000)
} else {
this.$vux.loading.hide()
}
},
// 初始化并配對裝置
_initBluetooth () {
if (!this.bluetoothPrinter) {
this.bluetoothPrinter = new Bluetooth()
this._loading(true)
console.log(this.bluetoothPrinter.status)
}
this.bluetoothPrinter.initState()
this.status = this.bluetoothPrinter.status
},
_printTest (msg) {
this.bluetoothPrinter.initPrinter()
this.bluetoothPrinter.setPrintPosition(1) // 居中 列印
this.bluetoothPrinter.printQrcode(msg)
this.bluetoothPrinter.feedPoint(20)
this.bluetoothPrinter.printTextNewLine('樣品111')
this.bluetoothPrinter.printTextNewLine('101013Q73898')
this.bluetoothPrinter.printTextNewLine('2020-10-10 09:33:33')
this.bluetoothPrinter.printTextNewLine('張三三')
this.bluetoothPrinter.printLine(3)
},
_printQrcode (msg) {
this.bluetoothPrinter.initPrinter()
this.bluetoothPrinter.printTabSpace(10)
// this.bluetoothPrinter.setPrintPosition(2)
this.bluetoothPrinter.printQrcode(msg)
},
feed (n) {
this.bluetoothPrinter.feedPoint(n)
},
_closeConnect () {
if (this.bluetoothPrinter) {
this.bluetoothPrinter.closeConnect()
}
},
_setPrintLocation (l, w) {
this.bluetoothPrinter.setPrintLocation(l, w)
},
_setPrintRotate (l) {
this.bluetoothPrinter.setPrintRotate(l)
},
_setCharacterScale (l) {
this.bluetoothPrinter.setCharacterScale(l)
},
_setPrintPosition (l) {
this.bluetoothPrinter.setPrintPosition(l)
}
}
}
</script>
<style scoped>
</style>
運作裝置及環境
IDE:Hbuilder X 2.8.13
測試機型:紅米 note4 android6.0
測試列印機:科密PB8001
列印指令類型:ESC/POS ESC/POS指令參考文檔
PS:
本文未提供連接配接藍牙裝置的方法,如有需要請點傳送門 —» H5+連接配接藍牙列印機
PPS:
隻初始化一次即可持續列印實作
可以把 new Bluetooth() 的執行個體的初始化放到store中進行管理,在需要的元件注入執行個體。代碼如下:
// store
const printer = {
namespaced: true,
state: {
bluetoothPrinter: null
},
mutations: {
setBluetoothPrinter (state, payload) {
state.bluetoothPrinter = payload
}
}
}
// component
export default {
data () {
return {
pagination: {
page: 0,
rows: 15
},
bottomList: [
{name: '添加', color: '#0D55A7'},
{name: '送出', color: '#11C827'},
{name: '标簽列印', color: '#F7AC0C'}
],
records: [],
recordsList: [],
printData: [],
refresh: false, // 上拉重新整理
loading: false, // 下拉加載
finished: false, // 是否擷取到了所有資料
submitStatus: false,
status: 0
}
},
computed: {
...mapState('printer', {
bluetoothPrinter: 'bluetoothPrinter'
})
},
watch: {
status () {
console.log('status==>', this.status)
if (this.status == 2) {
this._loading(false)
}
}
},
mounted () {
this._initBluetooth()
},
destroyed () {
console.log('destroyed!')
// this._closeConnect()
},
methods: {
_add () {
this.$store.commit('steel/removeInsSteelItem')
this.$jump('typeA-insScrapSteelContractEdit', {sampleCode: '添加/編輯基本資訊'})
},
// 全選
_allCheck () {
if (this.records.length === this.recordsList.length) {
this.records = []
return
}
this.records = this.recordsList.map(item => item.id)
},
// 送出
async _submitById () {
if (!this.records.length) {
this.$toast('至少選擇一個')
return
}
if (this.submitStatus) return
this.submitStatus = true
this.$vux.loading.show({
text: '正在送出中...'
})
const result = await waitInsScrapSteelSubmit(this.records)
if (result) {
this._resultChange('送出成功!')
this.$vux.loading.hide()
} else {
this._resultChange('網絡問題,請重新送出!')
this.$vux.loading.hide()
}
},
_resultChange (msg) {
this.$toast(msg)
this._onRefresh()
},
// 上拉重新整理
async _onRefresh () {
this.pagination.page = 0
this.recordsList = []
this.printData = []
await this._onLoad()
this.refresh = false
},
// 下拉加載
async _onLoad () {
this.pagination.page++
await this._waitInsScrapSteel()
this.loading = false
return true
},
_loading (flag) {
if (flag) {
this.$vux.loading.show({
text: '裝置配對中'
})
setTimeout(() => {
this.$vux.loading.hide()
}, 5000)
} else {
this.$vux.loading.hide()
}
},
// 初始化并配對裝置
_initBluetooth () {
if (!this.bluetoothPrinter) {
const obj = new Bluetooth()
this._loading(true)
this.$store.commit('printer/setBluetoothPrinter', obj)
console.log(this.bluetoothPrinter.status)
this.bluetoothPrinter.initState()
this.status = this.bluetoothPrinter.status
}
},
_closeConnect () {
if (this.bluetoothPrinter) {
this.bluetoothPrinter.closeConnect()
}
},
// 待列印資料
_selectData () {
if (!this.records.length) {
this.$toast('至少選擇一個')
return false
} else {
const {records, recordsList} = this
this.printData = []
let data = []
for (let i = 0; i < records.length; i++) {
for (let j = 0; j < recordsList.length; j++) {
if (records[i] === recordsList[j].id) {
data.push(recordsList[j])
}
}
}
this.printData = [...data]
}
},
// 列印方法
_print (data) {
this.bluetoothPrinter.initPrinter()
this.bluetoothPrinter.setPrintPosition(1) // 居中 列印
this.bluetoothPrinter.printQrcode(data.sampleCode) // 二維碼 樣品編号
this.bluetoothPrinter.feedPoint(20)
this.bluetoothPrinter.printTextNewLine(data.name) // 物料名稱
this.bluetoothPrinter.printTextNewLine(data.sampleCode) // 二維碼 樣品編号
this.bluetoothPrinter.printTextNewLine(this.$getTime(data.obtainSampleTime, true)) // 取樣時間
this.bluetoothPrinter.printTextNewLine(data.obtainSampler) // 取樣人
this.bluetoothPrinter.feedLine(4)
},
// 列印标簽
_printLabel () {
this._selectData()
const {printData} = this
const len = printData.length
for (let i = 0; i < len; i++) {
this._print(printData[i])
}
},
_dataBack (msg) {
switch (msg) {
case '添加':
this._add()
break
case '送出':
this._submitById()
break
case '标簽列印':
this._printLabel()
break
}
}
}
}
Demo
github位址:H5-bluetooth