Android(4.4-API 19)生成PDF后无预览网络打印实现求助
别着急!你的需求完全可以实现,我来一步步给你讲清楚怎么做,尤其是针对新手的友好方案~
带预览打印是Android官方支持的标准流程,非常适合新手上手,而且能让用户选择网络打印机(只要打印机和设备在同一局域网)。
你已经能生成PDF文件了,接下来只需要调用系统的打印服务,把生成好的PDF传递给它就行。所有代码都放在你那个有表单和Print按钮的Activity里,直接写在按钮的点击事件中:
步骤1:添加权限(如果需要)
如果你的PDF文件存在公共存储目录(比如你现在的/storage/emulated/0/client pqr/),需要在AndroidManifest.xml中添加存储权限:
<!-- Android 10及以下 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- Android 11+ 如需访问公共目录,可添加这个权限(需要用户手动授权) --> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
注意:Android 10+推荐把文件放在应用私有目录,这样不需要额外权限,但你如果坚持用公共目录,要记得在运行时请求权限。
步骤2:按钮点击事件中的打印代码
直接在Print按钮的点击监听里写这些代码:
printButton.setOnClickListener(v -> { // 指向你生成好的PDF文件 File pdfFile = new File("/storage/emulated/0/client pqr/pqr.pdf"); // 先检查文件是否存在 if (!pdfFile.exists()) { Toast.makeText(this, "PDF文件找不到啦!", Toast.LENGTH_SHORT).show(); return; } // 获取系统打印管理器 PrintManager printManager = (PrintManager) getSystemService(Context.PRINT_SERVICE); // 给打印任务起个名字,会显示在打印队列里 String printJobName = getString(R.string.app_name) + " - PQR表单打印"; // 适配Android 10+的简单方案:直接用FilePrintDocumentAdapter PrintDocumentAdapter printAdapter = new FilePrintDocumentAdapter(pdfFile); // 触发打印预览界面 printManager.print(printJobName, printAdapter, null); });
这段代码会弹出系统自带的打印预览界面,用户可以选择已发现的网络打印机,调整打印设置后直接打印,完全符合你的“至少带预览”的需求。
如果你的设备系统版本低于Android 10,FilePrintDocumentAdapter可能不存在,那可以自己写一个简单的PDF打印适配器(代码如下),替换上面的printAdapter即可:
// 在你的Activity内部定义这个内部类 private class CustomPdfPrintAdapter extends PrintDocumentAdapter { private final File pdfFile; public CustomPdfPrintAdapter(File pdfFile) { this.pdfFile = pdfFile; } @Override public void onLayout(PrintAttributes oldAttrs, PrintAttributes newAttrs, CancellationSignal cancelSignal, LayoutResultCallback callback, Bundle extras) { if (cancelSignal.isCanceled()) { callback.onLayoutCancelled(); return; } // 描述打印文档的信息 PrintDocumentInfo docInfo = new PrintDocumentInfo.Builder("pqr.pdf") .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT) .setPageCount(PrintDocumentInfo.PAGE_COUNT_UNKNOWN) // 不知道页数就设为未知 .build(); callback.onLayoutFinished(docInfo, !oldAttrs.equals(newAttrs)); } @Override public void onWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancelSignal, WriteResultCallback callback) { InputStream input = null; OutputStream output = null; try { input = new FileInputStream(pdfFile); output = new FileOutputStream(destination.getFileDescriptor()); byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = input.read(buffer)) != -1 && !cancelSignal.isCanceled()) { output.write(buffer, 0, bytesRead); } if (cancelSignal.isCanceled()) { callback.onWriteCancelled(); } else { callback.onWriteFinished(new PageRange[]{PageRange.ALL_PAGES}); } } catch (IOException e) { callback.onWriteFailed(e.getMessage()); e.printStackTrace(); } finally { try { if (input != null) input.close(); if (output != null) output.close(); } catch (IOException e) { e.printStackTrace(); } } } }
使用时替换成:
PrintDocumentAdapter printAdapter = new CustomPdfPrintAdapter(pdfFile);
无预览直接发送到网络打印机是可行的,但需要跳过系统打印服务,直接通过网络协议(比如IPP,大部分网络打印机都支持)发送PDF文件。这对新手来说门槛较高,因为需要处理:
- 网络打印机的IP地址、端口(通常是631)
- IPP协议的请求构造
- 可能的打印机认证
- 局域网内的打印机发现(可选)
如果你一定要做,可以尝试用第三方的IPP客户端库,或者自己实现简单的IPP请求,但这个过程涉及较多网络编程知识,建议先把带预览的版本跑通,再慢慢研究这部分。
所有打印相关的代码都直接放在你的表单Activity里:
- 按钮的点击监听就在这个Activity里,所以打印逻辑写在监听内部最直接。
- 如果是自定义的
PrintDocumentAdapter,可以作为Activity的内部类定义,这样方便访问Activity的上下文和资源。
- 测试时确保你的Android设备和网络打印机在同一个Wi-Fi局域网内,系统才能发现打印机。
- 如果生成PDF的过程比较耗时,建议放在子线程里执行,避免阻塞UI线程,点击按钮时可以先显示加载提示,生成完成后再触发打印。
内容的提问来源于stack exchange,提问作者Sam




