文章目录
- 1. sdk下载
- 2. 开始开发
- 2.1 打印之前准备工作
- 2.2 打印机是否连接检测
- 2.3 打印框架设计
最近有个需求是要连接 德佟打印机 进行打印相关事宜, 现在就遇到的问题简单阐述一下。

1. sdk下载
我们首先需要在官网下载对应的SDK,地址为:https://www.detonger.com/#/sdk/detail?sdkID=16BC0F46-ACC4-4EBB-9340-47328936E779
下载之后,务必请仔细阅读它的文档:

最重要的是需要铭记,需要开启蓝牙开关和定位开关(GPS),谨记谨记!
2. 开始开发
因为已经开发上线了,所以我就把我踩过的坑用代码整理出来,供大家有类似需求的避坑:
2.1 打印之前准备工作
我的建议是,专门有个类来检测打印环境是否满足要求,不然环境不匹配,根本就打印不了,这是我目前碰到的一些问题,所以进行打印之前的预检测,目前就只检查了蓝牙和 GPS 状态,因为这是硬性条件。
public static Pair<Integer,String> checkPrintEnvironment(){//1. 蓝牙是否打开BluetoothManagerHelper managerHelper = new BluetoothManagerHelper(MyApp.getInstance());if (!managerHelper.isBluetoothEnabled()){return new Pair<>(-1,"请打开蓝牙");}//3. 蓝牙状态不可用if (!managerHelper.isBluetoothAvailable()){return new Pair<>(-2,"蓝牙状态不可用,请检查蓝牙设置");}//2. 蓝牙权限不可用if (!managerHelper.hasBluetoothPermission()){return new Pair<>(-3,"蓝牙权限异常,请开启相关权限");}//4. gps状态检查if (!GPSUtils.isOpen(MyApp.getInstance())){return new Pair<>(-4,"GPS未打开,请打开GPS");}//TODOreturn new Pair<>(0,"打印环境正常");}
2.2 打印机是否连接检测
在打印之前,我们需要监测是否存在打印机连接,如果没有,需要告之用户进行打印机连接:
List<IDzPrinter.PrinterAddress> allPrinterAddress = CustomPrintManager.getInstance().getAllPrinterAddress();
if (null == allPrinterAddress || allPrinterAddress.isEmpty()){return new Pair<>(false, "没有找到打印机");
}
2.3 打印框架设计
因为需求要求可能会打印多次,而且每次的打印任务可能不一样,有时候可能只打印文字,但有时候可能需要打印图片,那么我们就需要设计一套队列打印打印系统,而且每一次打印都是比较耗时和异步的,所以框架设计必须满足:
- 可同时多次提交多个打印任务,
- 打印任务可能都不一样
- 打印机按照任务提交的顺序进行打印(这里没有做优先级设计)
大概的流程图应该按照如下方式:

那么按照以上的逻辑,我们来进行设计打印框架:
首先需要定义一个在整个打印流程中,可以传递的接口, 这个接口贯穿了一次打印从开始到结束的整个事件,用于记录打印机的状态和可能发生的问题,我们便于进行管控
public interface PrintTaskDownCallback {/*** 打印任务发生改变状态*/void onPrintTaskDown(int status, String message);}
下面,我们就需要进行定义一个异步执行 Task,这个 Task 接口是将整个打印流程拆分成的最小单位。一个打印任务中可能存在连接任务
,多个绘制文字任务
和 多个绘制图片任务
,所以我们需要抽象出来:
public interface AsyncPrintTask {int CONNECT_TASK = 0;int PRINT_TASK = 1;void nextRun(PrintTaskDownCallback task);PrintLogicCallback getPrintLogicCallback();int getTaskType();}
这里的 PrintLogicCallback
主要是记录日志所用:
/*** 打印回调*/
public interface PrintLogicCallback {void onPrintLogicInfo(int taskType, int code, String msg);
}
现在,我们就需要定义最重要的打印队列了,采用 first in first out
原则,我们采用LinkedList
进行封装:
public class PrintTaskQueue {private final Queue<AsyncPrintTask> taskQueue = new LinkedList<>();private boolean isRunning = false;//提交任务public synchronized void submitTask(AsyncPrintTask... taskList) {if (taskList == null || taskList.length == 0) {return;}for (AsyncPrintTask task : taskList){taskQueue.offer(task);}if (!isRunning) {isRunning = true;runNextTask();}}private synchronized void runNextTask() {if (taskQueue.isEmpty()) {isRunning = false;return;}// 取出队列中的第一个任务AsyncPrintTask task = taskQueue.poll();if (task != null) {isRunning = true ;task.nextRun((status, message) -> {if (task.getPrintLogicCallback() != null) {task.getPrintLogicCallback().onPrintLogicInfo(task.getTaskType(), status, message);}if (task.getTaskType() == AsyncPrintTask.CONNECT_TASK) {// 连接任务完成后,继续执行下一个任务// 可以根据 status 判断连接完成runNextTask();} else {// 可以根据 status 判断当前任务是否完成runNextTask();}});}}public void clear(){taskQueue.clear();isRunning = false;}}
稍微解释一下主体的逻辑,例如存在三个任务:TaskA,TaskB 和 TaskC,现在的想法就是先把 TaskA,TaskB 和 TaskC 放入到队列中,然后先取出 TaskA,等 TaskA 执行完成,再去取 TaskB,等 TaskB 任务完成,再去取 TaskC,直接队列中数据为空,打印任务结束。那么以上的 PrintTaskQueue
就是该方式的实施。
现在,我们就可以实现相关的具体 Task 了。
比如,我们要先实现一个连接任务:
/*** 打印机连接任务*/
public class ConnectTaskImpl implements AsyncPrintTask{private final PrintLogicCallback printLogicCallback;public ConnectTaskImpl(PrintLogicCallback printLogicCallback) {this.printLogicCallback = printLogicCallback;}@Overridepublic void nextRun(PrintTaskDownCallback task) {//CustomPrintManager.getInstance().gotoConnectTask(task);//具体去连接打印机任务}@Overridepublic PrintLogicCallback getPrintLogicCallback() {return printLogicCallback;}@Overridepublic int getTaskType() {return CONNECT_TASK;}}
其次,现在要实现打印文字的任务:
public class AsyncPrintTextTaskImpl implements AsyncPrintTask{private final String content;private final PrintLogicCallback printLogicCallback;public AsyncPrintTaskImpl(String content, PrintLogicCallback printLogicCallback) {this.content = content;this.printLogicCallback = printLogicCallback;}@Overridepublic void nextRun(PrintTaskDownCallback task) {//CustomPrintManager.getInstance().gotoPrintText(tagEntity, task);}@Overridepublic PrintLogicCallback getPrintLogicCallback() {return printLogicCallback;}@Overridepublic int getTaskType() {return PRINT_TASK;}}
然后,我们可以定义一个打印图片的任务:
public class AsyncPrintImageTaskImpl implements AsyncPrintTask{private final Bitmap image;private final PrintLogicCallback printLogicCallback;public AsyncPrintQRTaskImpl(Bitmap image, PrintLogicCallback printLogicCallback) {this.image = image;this.printLogicCallback = printLogicCallback;}@Overridepublic void nextRun(PrintTaskDownCallback task) {//CustomPrintManager.getInstance().gotoImagePrint(image, task);}@Overridepublic PrintLogicCallback getPrintLogicCallback() {return printLogicCallback;}@Overridepublic int getTaskType() {return PRINT_TASK;}
}
现在,已经定义了各种任务的实现,我们整合起来,提交任务可以写成这样:
public class PrinterSDK {private static final PrinterSDK instance = new PrinterSDK();private final PrintTaskQueue taskQueue = new PrintTaskQueue();public static PrinterSDK getInstance(){return instance;}// 前期准备public Pair<Boolean,String> prepare(){Pair<Integer, String> environmentCheckResult = EnvironmentCheckUtils.checkPrintEnvironment();if (environmentCheckResult.first != 0){return new Pair<>(false, environmentCheckResult.second);}List<IDzPrinter.PrinterAddress> allPrinterAddress = CustomPrintManager.getInstance().getAllPrinterAddress();if (null == allPrinterAddress || allPrinterAddress.isEmpty()){return new Pair<>(false, "没有找到打印机");}CustomPrintManager.getInstance().preparePrint();return new Pair<>(true, "准备完成");}public void commitPrinterPrepare(){taskQueue.submitTask(new ConnectTaskImpl(null));}/*** 提交打印文字任务*/public void commitPrintText(String text,PrintLogicCallback callback){taskQueue.submitTask(new ConnectTaskImpl(callback),new AsyncPrintTextTaskImpl(entity,callback));}/*** 提交打印图片任务*/public void commitPrintImage(Bitmap bitmap, PrintLogicCallback callback){taskQueue.submitTask(new ConnectTaskImpl(callback),new AsyncPrintImageTaskImpl(bitmap,callback));}
现在,最重要的是CustomPrintManager
, 这个是类似底层,与打印机交互的底层语言了, 这里我就不贴了,基本上就是根据德佟
的 SDK 进行封装一下即可。
最后来贴一下成果:
图片 | 图片+ 文字 |
---|---|
![]() | ![]() |