安卓使用usb调取打印机
/**
* 安卓usb调取打印机
*@param { string | bytes[] } html 传入的打印内容
*传入一段文本或一个bytes数组
* @returns
*/
export const printUsb = (html) => {
return new Promise((resolve, reject) => {
if (!window.plus) return reject(new Error("请在安卓环境中使用!"));
//如果参数不是字符串或bytes数组直接报错
if (!Array.isArray(html) && typeof html !== "string")
return reject(new Error("参数不正确!"));
try {
const context = plus.android.runtimeMainActivity();
const usbManager = context.getSystemService("usb");
//引入usb类
plus.android.importClass(usbManager);
//获取到设备列表
const devices = usbManager.getDeviceList();
const values = plus.android.invoke(devices, "values");
//调用values方法获取usb设备列表
const deviceList = plus.android.invoke(values, "toArray");
const printerList = deviceList.filter((item) => {
const usbInterface = plus.android.invoke(item, "getInterface", 0);
const usbType = plus.android.invoke(usbInterface, "getInterfaceClass");
//usb类型为7的时候是打印机
if (usbType === 7) return item;
});
//如果打印机不存在,直接阻断
if (!printerList.length) return reject(new Error("请连接打印机设备!"));
//usb设备(我这里选择打印机的第一台连接,如果要连多台打印机可以用上面获取的pinterList打印机列表进行操作)
const device = printerList[0];
const PendingIntent = plus.android.importClass(
"android.app.PendingIntent",
);
const Intent = plus.android.importClass("android.content.Intent");
//申请usb传输权限
const pendingIntent = PendingIntent.getBroadcast(
context,
0,
new Intent("ACTION_USB_PERMISSION"),
PendingIntent.FLAG_UPDATE_CURRENT,
);
//判断是否具有权限
const isExist = plus.android.invoke(usbManager, "hasPermission", device);
//如果权限不存在申请权限
if (!isExist) {
//请求读写权限
usbManager.requestPermission(device, pendingIntent);
return resolve('已获取usb权限!');
}
//建立连接
const socket = usbManager.openDevice(device);
if (!socket) return reject(new Error("usb连接失败!"));
const iface = plus.android.invoke(device, "getInterface", 0);
plus.android.invoke(socket, "claimInterface", iface, true);
//批量传输示例
const endpoint = plus.android.invoke(iface, "getEndpoint", 0);
//根据传入的内容类型做处理
const buffer =
typeof html === "string"
? plus.android.invoke(html, "getBytes", "gbk")
: html;
plus.android.invoke(
socket,
"bulkTransfer",
endpoint,
buffer,
buffer.length,
5000,
);
//释放usb端口资源
plus.android.invoke(socket, "releaseInterface", iface);
//关闭usb连接
plus.android.invoke(socket, "close");
resolve("打印成功!");
} catch (error) {
reject(error);
}
});
};
安卓使用蓝牙调取打印机设备
/**
*安卓使用蓝牙调取打印机
*@param { string } deviceId 蓝牙的mac地址(即设备id)
*@param { string } html 需要打印的文本
*/
export const printBluetooth(deviceId, html) {
return new Promise((resolve, reject) => {
try {
plus.android.runtimeMainActivity();
const BluetoothAdapter = plus.android.importClass(
"android.bluetooth.BluetoothAdapter",
);
const UUID = plus.android.importClass("java.util.UUID");
const uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
const Adapter = BluetoothAdapter.getDefaultAdapter();
Adapter.cancelDiscovery(); //停止扫描
const device = Adapter.getRemoteDevice(deviceId);
plus.android.importClass(device);
const bluetoothSocket =
device.createInsecureRfcommSocketToServiceRecord(uuid);
plus.android.importClass(bluetoothSocket);
if (!bluetoothSocket.isConnected()) {
bluetoothSocket.connect();
}
const outputStream = bluetoothSocket.getOutputStream();
plus.android.importClass(outputStream);
const bytes = plus.android.invoke(html, "getBytes", "gbk");
outputStream.write(bytes);
outputStream.flush();
outputStream.close();
resolve();
} catch (error) {
reject(error);
}
});
}
热敏打印机配置参数及简单模板
(部分命令可能不一致,需要查找对应品牌的打印机指令)
const printer = {
//初始化打印机
start: "\x1B\x40",
//左边距
leftPadding: "\x1D\x4C\x02\x00",
//右边距
rightPadding: "\x1D\x57\x02\x00",
//首行缩进两字符
textIndent:'\x1B\x5C\x18\x00',
//文本左对齐
alignLeft: "\x1B\x61\x00",
//文本居中
alignCenter: "\x1B\x61\x01",
//文本右对齐
alignRight: "\x1B\x61\x02",
//字体缩小
textSmall: "\x1B\x21\x00",
//字体放大
textLarge: "\x1D\x21\x11",
//恢复默认字体
textRecover: "\x1D\x21\x00",
//字体加粗
bold: "\x1B\x45\x01",
//取消字体加粗
boldOff: "\x1B\x45\x00",
//字体双倍高度
doubleHeight: "\x1B\x33\x30",
//恢复行高
lineHeightRecover: "\x1B\x32",
//设置行间距
lineSpacing: `\x1B\x33\x24`,
//换行
lineBreak: "\x0A",
//禁止自动换行
tabOff: "\x1B\x57\x00",
//恢复自动换行
tab: "\x1B\x31\x01",
//切纸 (全切)
end: "\x1B\x69",
//切纸 (半切)
endHalf: "\x1B\x6D",
//分割线
devide: `\x1B\x61\x01${"-".repeat(48)}\x0A\x1B\x61\x00`,
//二维码
qrcode: () => {
return;
},
};
//计算中间空白间隔
function letterSpace(str) {
const length = [...str].reduce((acc, char) =>
//中文unicode编码大于255(中文一个字占2个字符,英文一个字一字符)
acc + (char.charCodeAt(0) > 255 ? 2 : 1), 0)
//80mm热敏打印机减去左右边距宽度为48字符
return ' '.repeat(48 - length);
}
const createTemplate = () => {
let escpos = `${printer.start}
${printer.alignCenter}${printer.bold}哆啦A梦餐厅
${printer.lineBreak}
${printer.alignCenter}${printer.bold}【收银凭证】${printer.lineBreak}
${printer.alignLeft}${printer.bold}贵宾客户${printer.lineBreak}
${printer.alignLeft}${printer.boldOff}2025/06/27 09:18${letterSpace('2025/06/27 09:18票号:0007')}${printer.bold}票号:0007${printer.lineBreak}
${printer.devide}
${printer.bold}1.麻婆豆腐${letterSpace('1.麻婆豆腐72元')}${printer.bold}72元${printer.lineBreak}
${printer.textSmall}${printer.textIndent}8件x9${printer.lineBreak}
${printer.devide}
${printer.textSmall}应付${letterSpace('应付72元')}${printer.bold}72元${printer.lineBreak}
${printer.textSmall}实付${letterSpace('实付(现金)72元')}${printer.bold}(现金)72元${printer.lineBreak}
${printer.devide}
${printer.textSmall}收银员:哆啦美${printer.lineBreak}
${printer.end}
`;
// 行4 (空行)
return escpos;
};
export default createTemplate;