UniApp蓝牙打印开发实战从权限适配到高性能封装在移动应用开发领域蓝牙打印功能已经成为零售、物流和医疗等行业应用的标配需求。UniApp作为跨平台开发的利器配合原生插件能够实现高效的蓝牙打印功能。但在实际开发中开发者往往会遇到各种坑——从Android 12新增权限导致的闪退问题到蓝牙连接不稳定、打印任务管理混乱等挑战。本文将分享一套经过实战检验的解决方案帮助开发者构建稳定可靠的蓝牙打印功能。1. Android蓝牙权限全版本兼容方案Android系统的权限管理随着版本迭代不断收紧这对蓝牙打印功能的兼容性提出了更高要求。特别是Android 12引入的BLUETOOTH_SCAN和BLUETOOTH_CONNECT权限如果不正确处理会导致应用在运行时直接闪退。1.1 权限声明配置在manifest.json中需要声明完整的蓝牙权限集合!-- 基础蓝牙权限 -- uses-permission android:nameandroid.permission.BLUETOOTH/ uses-permission android:nameandroid.permission.BLUETOOTH_ADMIN/ uses-permission android:nameandroid.permission.ACCESS_COARSE_LOCATION/ !-- Android 12新增权限 -- uses-permission android:nameandroid.permission.BLUETOOTH_CONNECT / uses-permission android:nameandroid.permission.BLUETOOTH_SCAN /注意从Android 6.0开始部分权限需要运行时申请特别是位置权限对于蓝牙设备发现至关重要。1.2 动态权限请求实现以下是一个完整的动态权限请求方案async function checkBluetoothPermissions() { const permissions [ android.permission.BLUETOOTH, android.permission.BLUETOOTH_ADMIN, android.permission.ACCESS_COARSE_LOCATION ]; // Android 12需要额外权限 if (plus.os.version 12) { permissions.push( android.permission.BLUETOOTH_CONNECT, android.permission.BLUETOOTH_SCAN ); } const results await uni.requestPermissions({ permissions: permissions }); // 检查每个权限的授权状态 for (const perm of permissions) { if (results[perm] ! 1) { return false; } } return true; }1.3 权限拒绝处理策略当用户拒绝权限时应当提供友好的引导if (!await checkBluetoothPermissions()) { uni.showModal({ title: 权限提示, content: 蓝牙打印功能需要蓝牙和位置权限请前往设置开启, confirmText: 去设置, success(res) { if (res.confirm) { plus.runtime.openSettings(); } } }); return; }2. LPAPI插件高级封装技巧直接使用原生插件API会导致代码难以维护。通过Promise化和模块化封装可以显著提升代码质量。2.1 基础Promise化封装const api uni.requireNativePlugin(DothanTech-LPAPI); function promisifyAPI(action, data {}) { return new Promise((resolve, reject) { if (!api || !api[action]) { reject(new Error(API方法${action}不存在)); return; } api[action](data, (result) { if (result?.code 0) { resolve(result.data || true); } else { reject(result?.data || 操作失败); } }); }); }2.2 增强型打印机管理类class PrinterManager { constructor() { this.currentPrinter null; this.printQueue []; this.isPrinting false; } // 获取打印机列表 async getPrinters() { try { const printers await promisifyAPI(getPrinters); return printers || []; } catch (e) { console.error(获取打印机列表失败:, e); return []; } } // 连接指定打印机 async connectPrinter(printerName) { try { await promisifyAPI(openPrinter, { name: printerName }); this.currentPrinter printerName; return true; } catch (e) { console.error(连接打印机失败:, e); throw e; } } // 添加打印任务到队列 enqueueJob(job) { this.printQueue.push(job); this._processQueue(); } // 处理打印队列 async _processQueue() { if (this.isPrinting || this.printQueue.length 0) return; this.isPrinting true; const job this.printQueue.shift(); try { await job(); } catch (e) { console.error(打印任务失败:, e); } finally { this.isPrinting false; this._processQueue(); } } }2.3 打印任务构建器模式class PrintJobBuilder { constructor() { this.commands []; } setOrientation(degrees) { this.commands.push(() promisifyAPI(setItemOrientation, degrees)); return this; } drawText(text, x, y, options {}) { this.commands.push(() promisifyAPI(drawText, { text, x, y, width: options.width || 50, height: options.height || 10, fontHeight: options.fontSize || 5, ...options })); return this; } drawQRCode(text, x, y, size) { this.commands.push(() promisifyAPI(draw2DQRCode, { text, x, y, width: size })); return this; } async print() { await promisifyAPI(startJob, { width: 80, height: 297 }); // A4宽度80mm for (const cmd of this.commands) { await cmd(); } await promisifyAPI(commitJob); await promisifyAPI(endJob); } } // 使用示例 new PrintJobBuilder() .drawText(订单号: 20230815001, 5, 5) .drawQRCode(https://example.com/order/20230815001, 5, 20, 30) .print();3. 蓝牙连接稳定性优化实战蓝牙连接的不稳定性是开发中最常见的问题之一。以下是经过验证的优化方案。3.1 连接状态监测与自动重连let reconnectAttempts 0; const MAX_RECONNECT_ATTEMPTS 3; async function checkPrinterConnection() { try { const isConnected await promisifyAPI(isPrinterOpened); if (!isConnected printerManager.currentPrinter) { if (reconnectAttempts MAX_RECONNECT_ATTEMPTS) { reconnectAttempts; await printerManager.connectPrinter(printerManager.currentPrinter); } else { console.warn(达到最大重连次数); reconnectAttempts 0; } } return isConnected; } catch (e) { console.error(检查连接状态失败:, e); return false; } } // 定时检查连接状态 setInterval(checkPrinterConnection, 30000);3.2 蓝牙信号强度监测async function monitorSignalStrength() { try { const printerInfo await promisifyAPI(getPrinterInfo); if (printerInfo?.rssi) { if (printerInfo.rssi -80) { console.warn(蓝牙信号弱可能影响打印质量); } return printerInfo.rssi; } } catch (e) { console.error(获取信号强度失败:, e); } return null; }3.3 连接超时与错误处理async function connectWithTimeout(printerName, timeout 10000) { let timeoutId; const timeoutPromise new Promise((_, reject) { timeoutId setTimeout(() { reject(new Error(连接超时)); }, timeout); }); try { await Promise.race([ printerManager.connectPrinter(printerName), timeoutPromise ]); } finally { clearTimeout(timeoutId); } }4. 高级打印功能实现4.1 复杂排版实现async function printReceipt(order) { const builder new PrintJobBuilder(); // 标题 builder.drawText(order.storeName, 0, 5, { fontHeight: 8, horizontalAlignment: 1, // 居中 width: 80 }); // 分隔线 builder.drawLine(5, 15, 75, 15, { lineWidth: 0.5 }); // 订单信息 let yPos 20; builder.drawText(订单号: ${order.orderNo}, 5, yPos); yPos 7; builder.drawText(时间: ${order.createTime}, 5, yPos); yPos 7; // 商品列表 builder.drawText(----------------------------, 5, yPos, { horizontalAlignment: 1 }); yPos 5; order.items.forEach(item { builder.drawText(item.name, 5, yPos); builder.drawText(¥${item.price} x ${item.quantity}, 60, yPos, { horizontalAlignment: 2 // 右对齐 }); yPos 5; }); // 底部信息 builder.drawText(谢谢惠顾, 0, yPos 10, { fontHeight: 6, horizontalAlignment: 1, width: 80 }); await builder.print(); }4.2 打印任务优先级管理class PriorityPrintQueue { constructor() { this.highPriorityQueue []; this.normalQueue []; } addJob(job, isHighPriority false) { const queue isHighPriority ? this.highPriorityQueue : this.normalQueue; queue.push(job); this._process(); } async _process() { if (this._isProcessing) return; this._isProcessing true; while (this.highPriorityQueue.length 0 || this.normalQueue.length 0) { const job this.highPriorityQueue.shift() || this.normalQueue.shift(); try { await job(); } catch (e) { console.error(打印任务执行失败:, e); } } this._isProcessing false; } }4.3 打印结果验证机制async function verifyPrintResult(expectedPages) { return new Promise((resolve) { let verified false; // 设置超时检查 const timeout setTimeout(() { if (!verified) { console.warn(打印结果验证超时); resolve(false); } }, 30000); // 监听打印机状态 const listener setInterval(async () { try { const pages await promisifyAPI(getJobPages); if (pages expectedPages) { verified true; clearInterval(listener); clearTimeout(timeout); resolve(true); } } catch (e) { console.error(验证打印结果时出错:, e); } }, 3000); }); }在UniApp中实现稳定可靠的蓝牙打印功能关键在于处理好权限兼容性、连接稳定性和任务管理这三个核心问题。通过本文介绍的高级封装技巧和实战方案开发者可以构建出适应各种业务场景的打印模块。实际项目中建议结合具体业务需求对打印队列管理、错误处理和性能监控等方面进行进一步优化。