Zebra打印集成实践
目的
Zebra ISV 技术团队多年来一直与开发人员合作。该小组提供开发人员支持和测试服务。我们根据我们经常看到的常见问题创建了这些最佳实践。我们希望为开发人员提供以下方面的指导:
-
我们已经多次看到的常见性能和稳定性错误。
-
如何为客户创造最佳的用户体验。
-
如何最好地利用 Zebra 的增值功能
由于我们最初发布了最佳实践来帮助避免其中一些问题,因此测试失败的数量已经减少,并且我们收到了更多关于如何实施它们的问题。本文档试图改进原始文档并使其更易于使用它们进行开发。
谁应该使用这个
本文档有几个主要受众。
-
软件开发人员编写代码以打印或管理 Zebra 打印机。
-
测试工程师正在寻找测试涉及 Zebra 打印机的应用程序的最佳方法。
-
用户体验工程师在涉及打印时寻求提供更好的建议。
-
希望让 Zebra 对其软件进行验证的 Zebra 合作伙伴。
本文档的组织方式
每个部分都有最佳实践的名称和描述。接下来是针对开发人员的“如何做”部分和针对测试人员的“如何测试”部分。任何一个部分都可能有代码片段或其他注释来详细说明如何实现每个部分。
本文档中的代码示例使用 Java for Android,假设使用 Link-OS 多平台 SDK 并使用 ZPL 打印语言。您可以使用几乎任何操作系统的几乎任何编程语言、任何 Zebra 打印机、任何打印页面描述语言(无论是否使用 SDK)实施这些最佳实践。SDK 使它更容易。此处的示例代码仅作为示例,可能需要进行调整以适合您的用例。可以在 Zebra Github 存储库中找到更多实施最佳实践的示例。如果您有实施方面的问题,请在 Zebra开发人员门户中提问。
在线开发文档: https://techdocs.zebra.com/link-os/
斑马样例库:https://github.com/Zebra
1. 开箱即用
您的应用程序应与您指定的 Zebra 打印机一起使用。如果打印机是全新的开箱即用,它应该可以与该打印机一起使用。并非所有打印机都具有相同的默认行为。默认设置可能无法满足您的应用程序的需要。
怎么做:
-
设置正确的连接(TCP、Cloud Connect、BT、BTLE、USB 等)
注意:可以在API 文档中找到不同连接类型的示例。http://techdocs.zebra.com/link-os/
-
设置正确的 Zebra 打印页面描述语言(ZPL、CPCL、line_print、PDF 等)
注意:请参阅页面描述语言部分中的代码示例。
-
设置标签和打印设置(打印速度、浓度、标签宽度、长度等) 代码
注意:有关 SGD(Set-Get-Do)设置的完整列表,请参阅ZPL 编程指南。建议您为您的用户提供一个界面,以便在您的应用中为他们的打印机调整这些设置。您可能希望根据这些设置调整打印输出。要在打印机中设置它们,您可以使用前面的代码。另请参阅Developer Portal上的博客。
-
(可选 - 如果需要)设置远程管理设置(连接器、镜像、配置文件管理器)
注意:有关在打印机中设置 Cloud Connect、连接器和 Profile Manager 的信息,请参阅有关 Weblink 命令的ZPL 编程指南。有关通过打印机上的 FTP 设置打印机管理的信息,请参阅镜像部分。
-
(可选 - 如果需要)设置特殊功能(ZBI、虚拟设备等)
-
(可选 - 如果需要)验证打印机固件版本 代码
-
验证是否满足以下部分的最佳实践
如何测试它:
-
获取新打印机或将打印机默认为出厂规格。按照以下页面上的安装驱动和设置应用程序。
https://www.zebra.cn/cn/zh/support-downloads/printer-software/printer-setup-utilities.html
-
有几种方法可以默认 Zebra 打印机,但一种常见的方法是使用 Setup Utility 软件。
-
安装设置实用程序 Setup Utility软件
-
连接到打印机
-
选择打印机工具
-
在“操作”下,选择“加载出厂默认值”
-
2. 稳定性
尝试打印时,应用程序不应崩溃或冻结。这包括在未通知用户原因的情况下无法打印。
怎么做:
-
始终在 UI 以外的线程上与打印机通信。
-
始终围绕任何打印机通信使用 try/catch 语句。
-
完成打印后关闭打印机连接。
相关代码如下
public class PrintTask extends AsyncTask{
protected void backgroudPrint(Void... params)
{
// Instantiate connection for ZPL TCP port at given address
Connection printerConnection = new TcpConnection(theIpAddress, TcpConnection.DEFAULT_ZPL_TCP_PORT);
try {
// Open the connection - physical connection is established here.
printerConnection.open();
// Set settings, check status, print, etc.
} catch (ConnectionException e) {
// Handle communications error here.
e.printStackTrace();
} finally {
try {
// Close the connection to release resources.
printerConnection.close();
} catch (ConnectionException ec) {
// Handle connection close error here.
如何测试它:
-
在运行应用程序时,在此过程中随机关闭打印机。验证应用程序不会崩溃或挂起。
-
在不同的时间打开它。确保应用程序仍然稳定并通知连接问题。
3. 安全
与打印机的通信应被视为潜在的安全风险。遵循您的组织或客户的安全最佳实践。默认情况下,打印机对大多数通信开放。
怎么做:
-
尽可能使用与打印机的安全通信方法,从蓝牙安全级别到使用 Wi-Fi 证书和 HTTPS 通信。
-
关闭您不打算使用的通信方法。询问您需要支持的特定协议/系统。
-
不要将个人信息作为存储格式或存储图像的一部分
注意:更完整的安全最佳实践集即将发布
如何测试它:
-
假设与打印机的通信存在潜在的安全风险并进行相应的测试。
请参阅从此处开始的SGD 通信命令。
-
假设存储在打印机中的所有数据(密码、证书和其他已知的安全文件和设置除外)都可以提取并进行相应的测试。
请参阅 ZPL 命令^HF、^HG和 SGD file.type
4. 格式化输出
客户希望他们的打印输出易于阅读和扫描。他们还希望自己的品牌引人注目。
怎么做:
-
尽可能使用 ZPL 打印页面描述语言。
注意:请参阅页面描述语言部分中的代码示例。
-
应至少使用图像,尤其是那些包含条形码的图像。图像使用大量数据,因此打印速度较慢。条形码在转换为图像时有时会失真。如果您必须使用图像,请确认 DPI 与打印机相同。
-
使用设计工具来帮助创建标签格式。查看Zebra Designer应用程序或联系我们的设计合作伙伴之一
-
根据客户反馈选择介质(纸张或标签纸)。我们推荐Zebra 认证耗材以获得最佳打印质量和打印机寿命。
-
使用Setup Utility应用程序设置打印机的打印质量并在您的应用程序中设置相同的设置。
-
适当设置打印浓度。如果条形码是要读取的最重要的数据,请将暗度设置为比读取文本的最佳值更亮。考虑为较浅的文本使用粗体。
如何测试它:
-
该应用程序以可接受的打印质量产生预期的打印输出。
-
条形码应为 B 级或更高。条码分级是使用条码验证工具完成的。这确保了条形码的可扫描性。如果您没有,我们可以与您合作以确保您的条形码是可扫描的。
-
打印输出不应超出页面、太小而无法阅读或间距太紧
最佳
5.页面描述语言
Zebra 打印机支持多种不同的格式化语言。不同的打印机使用不同的默认格式语言。
怎么做:
-
设置您打算在 SDK 中使用的页面描述语言。
-
设置您打算在打印机中使用的页面描述语言。这是两个不同的步骤。有关选项,请参阅ZPL 指南。
-
-
验证语言是您想要的,因为并非所有打印机都支持所有命令语言。 见上面的代码.
注意:推荐使用 ZPL,因为:
-
这是 Zebra 致力于不断改进的语言。大多数其他语言仅支持用于错误修复。
-
它是具有最佳字体和本地化功能的语言。
-
它是几乎每台 Zebra 打印机都附带的一种语言,因此您可以从一台打印机切换到另一台打印机,而无需更改您的应用程序。
-
如何测试它:
-
使用您打算支持的不同打印机型号进行测试。
-
更改页面描述语言并确认应用程序仍然有效。验证打印机接受更改。
使用设置实用程序设置和验证页面描述语言。有关选项,请参阅ZPL 指南。
-
在 Android 上 - 选择“设备语言”,然后选择“设置设备语言”以将语言选择为“ZPL”。选择“应用”并验证显示的“当前设备语言”。
-
在 PC 上 - 选择“打开与打印机的通信”。在顶部框中输入:
! U1 setvar "device.languages" "zpl"
! U1 getvar "device.languages"点击输入。换行符非常重要,并且完全如图所示使用直双引号。单击“发送到打印机”两次。在大多数 ZPL 打印机上,响应应该是:“hybrid_xml_zpl”。
-
安装设置实用程序软件
-
连接到打印机
-
设置页面描述语言
-
在您的应用程序中测试打印。
-
将设备语言更改为“line_print”并验证,如步骤 3 所示。
-
在您的应用程序中测试打印。
-
最佳
6.状态
状态将告诉您打印机是否准备好打印或处于错误状态。
怎么做:
-
打印前检查打印机的状态,确保打印机处于准备打印状态。
-
检查打印期间和打印后的状态,以确保打印成功。
-
另一种选择是使用打印机警报系统。可以将打印机设置为在打印机进入错误状态时在特定端口上发送通知。这对于始终连接到打印机的服务器端应用程序(24/7 用例)最有用。
-
建议应用程序等待发送打印作业,直到清除所有错误。
-
提供在打印过程中出现的错误重印。
-
状态通道是检查状态的首选方法。这应该会提高性能。
-
您还可以使用打印机里程表检查打印是否完成。这可能比此验证的状态检查更准确,但也可能没有必要。
如何测试它:
-
打印前,打开介质门或取出纸张。
-
在打印过程中,打开介质门。
这些问题是否会导致应用不稳定?
-
验证以下内容:
-
媒体门打开
-
出纸
-
打印机无法访问(关闭或断开连接/超出范围)。
-
色带输出
-
打印头太热(高浓度、高速、大量黑色)
-
暂停
-
接收缓冲区已满(快速发送多个作业)
-
7. 显示打印机错误状态
应提醒用户注意打印机的状态问题。他们不应该查看打印机来发现这一点。
怎么做:
-
检查状态时,提醒用户您的应用程序中打印机上发生的确切错误。
在 Android 中,您可以使用 Toast、Java 和 C# - ShowDialog 等……
如何测试它:
-
在测试状态问题时,应用程序是否会以明确的最终用户语言提醒用户,确切的打印机问题是什么?
验证以下状态:
-
媒体门打开
-
出纸
-
打印机无法访问(关闭或断开连接/超出范围)。
-
色带输出
-
打印头太热(高浓度、高速、大量黑色)
-
暂停
-
接收缓冲区已满(快速发送多个作业)
-
8. 性能
打印机性能是根据几个因素来衡量的。打印时间(用户激活打印操作和打印机开始打印之间的时间)和移动打印机电池寿命是受软件交互影响的一些最重要的性能问题
怎么做:
-
使用打印页面描述语言来优化性能,如果可能避免使用图形,我们建议使用模板或格式。有关格式打印的详细信息,请参阅API 参考。
-
RFID 编码或 BTLE 连接 -
-
不要以每种格式发送内联图形。
-
使用打印页面描述语言而不是图像进行打印。
-
将图形和格式存储在打印机中,以最少的数据传输进行调用。
-
-
在移动打印机中,设置睡眠模式并关闭连接以节省电池寿命。并非在所有打印机上都可用
-
使用状态通道优化打印时间。有关详细信息,请参阅状态部分。
-
为了快速连接和配对,您可以使用 NFC(打印触摸)或扫描进行连接。 示例代码
-
使用虚拟设备时,请确认虚拟设备正在打印机上运行。示例代码
如何测试它:
-
可接受的打印时间取决于您的用例。
-
电池寿命健康通过充电循环计数来衡量。
要检查您的电池健康状况,请使用Setup Utility软件。使用命令检查:
! U1 getvar "power.health"
后跟 Enter
• 如果 power.cycle_count < 300 且容量比(实际容量与
设计容量的比率)大于或等于 0.80,则运行状况为“良好”。
• 如果power.cycle_count 介于300 和600 之间,则运行状况为“replace”。如果# of Cycles < 550 但> 300,
打印机将显示一条消息“请更换电池组”,然后发出三声哔声。如果
充电周期数≤550 但< 600,则提示应为:“警告 - 电池已过
使用寿命”,然后发出三声哔哔声。
• 如果power.cycle_count 大于600,则运行状况为“差”。打印机将闪烁一条消息:“请在继续
之前更换电池– 关机”并伴随30 秒的哔哔声,
然后关闭。
常问问题
如果……我该怎么办?
我的应用程序在与打印机通信时崩溃了?
如果您认为应用程序崩溃是因为您正在与打印机通信:
-
设备可能因为超出范围或打印机关闭而无法通信,因此会引发异常。确保与打印机的所有通信都在 try/catch 语句中。
public class PrintTask extends AsyncTask
{
protected void backgroudPrint(Void... params)
{
// Instantiate connection for ZPL TCP port at given address
Connection printerConnection = new TcpConnection(theIpAddress, TcpConnection.DEFAULT_ZPL_TCP_PORT);
try {
// Open the connection - physical connection is established here.
printerConnection.open();
// Set settings, check status, print, etc.
} catch (ConnectionException e) {
// Handle communications error here.
e.printStackTrace();
} finally {
try {
// Close the connection to release resources.
printerConnection.close();
} catch (ConnectionException ec) {
// Handle connection close error here.
ec.printStackTrace();
}
}
}
}
-
验证您具有适当的通信权限(请参阅文档)
-
与打印机通信有时需要一些时间,有时需要几秒钟。将其作为一项长期运行的任务来处理。始终在 UI 以外的线程上与打印机通信。(见上面的代码)
如果您担心未打印打印作业:
-
要验证打印作业是否已发送和打印,有两个选项。结合使用,它们可以在关键任务打印应用中为您提供帮助:
-
在打印过程中检查打印状态 代码
-
跟踪打印机中的里程表以检查打印的标签。 代码
-
如果……我该怎么办?
我的打印机不打印或不打印我想要的内容?
-
检查并显示打印机状态。打印机可能处于无法打印的良好状态。
// Check during / after printing
private boolean postPrintCheckPrinterStatus(Connection connection)
{
ZebraPrinter printer = ZebraPrinterFactory.getLinkOsPrinter(connection, PrinterLanguage.ZPL);
if (null == printer) {
printer = ZebraPrinterFactory.getInstance(PrinterLanguage.ZPL, connection);
}
PrinterStatus printerStatus = printer.getCurrentStatus();
// loop while printing until print is complete or there is an error
while ((printerStatus.numberOfFormatsInReceiveBuffer > 0) && (printerStatus.isReadyToPrint))
{
Thread.sleep(500);
printerStatus = printer.getCurrentStatus();
}
if (printerStatus.isReadyToPrint) {
System.out.println("Ready To Print");
return true;
} else if (printerStatus.isPaused) {
System.out.println("Cannot Print because the printer is paused.");
} else if (printerStatus.isHeadOpen) {
System.out.println("Cannot Print because the printer head is open.");
} else if (printerStatus.isPaperOut) {
System.out.println("Cannot Print because the paper is out.");
} else {
System.out.println("Cannot Print.");
}
return false;
}
-
验证页面描述语言是否设置为您想要的。
// Set settings, check status, print, etc.
if (setPrintLanguage(statusConnection) && checkPrinterStatus(statusConnection))
{
int labelCount = Integer.parseInt(SGD.GET("odometer.total_label_count", statusConnection));
// Send Print Job (1 label)
String zplData = "^XA^FO20,20^A0N,25,25^FDThis is a ZPL test.^FS^XZ";
printerConnection.write(zplData.getBytes());
if (postPrintCheckPrinterStatus(statusConnection))
{
int newLabelCount = Integer.parseInt(SGD.GET("odometer.total_label_count", statusConnection));
if (newLabelCount == labelCount + 1)
{
System.out.println("Print Successful.");
}
}
//else reprint?
}
-
验证您在应用程序中具有适当的通信权限(请参阅文档)
-
验证您的 ZPL 是否正确
-
使用打印机网页预览
-
通过第三方网页预览http://labelary.com/viewer.html
-
使用ZebraDesigner等标签设计工具设计您的标签。
-
-
校准打印机(ZPL 命令^JC,或查看您的特定打印机用户指南)
-
验证浓度、标签尺寸和其他设置是否正确(请参阅设置实用程序)
最佳
如果……我该怎么办?
打印需要很长时间?
-
打印最慢的部分往往是数据传输速度。要优化这一点,请通过以下方式减少发送到打印机的数据量:
-
使用页面描述语言
-
避免使用图形并确认必要的图形很小
-
使用模板或存储格式(参见Github上的代码)
-
-
使用状态通道检查状态和设置
// With Bluetooth you have to open a raw connection before opening a status connection.
Connection btConnection = new BluetoothConnection(theBtMacAddress);
btConnection.open();
Connection btStatusConnection = new BluetoothStatusConnection(theBtMacAddress);
// or
Connection nwStatusConnection = new TcpStatusConnection(theIpAddress, TcpStatusConnection.DEFAULT_STATUS_TCP_PORT);
-
将打印速度设置为不影响打印质量的最快设置。
-
如果您要在短时间内打印多个作业,请不要在每次打印后关闭连接。使用计时器来决定何时关闭连接