打印 HTML 文档

在 Android 上打印照片以外的内容,需要在打印文档中组合文本和图形。Android 框架提供了一种使用 HTML 组合文档并以最少的代码进行打印的方式。

在 Android 4.4(API 级别 19)中,已更新 WebView 类,以启用 HTML 内容的打印。该类允许您加载本地 HTML 资源或从网络下载页面,创建打印作业并将其交给 Android 的打印服务。

本课程介绍如何快速构建包含文本和图形的 HTML 文档,以及如何使用 WebView 进行打印。

加载 HTML 文档

使用 WebView 打印 HTML 文档涉及加载 HTML 资源或将 HTML 文档构建为字符串。本部分介绍如何构建 HTML 字符串并将其加载到用于打印的 WebView 中。

该视图对象通常用作 activity 布局的一部分。但是,如果您的应用未使用 WebView,则可以专门为此打印目的创建一个该类的实例。创建此自定义打印视图的主要步骤包括:

  1. 创建一个 WebViewClient,以便在 HTML 资源加载后启动打印作业。
  2. 将 HTML 资源加载到 WebView 对象中。

以下代码示例演示如何创建一个简单的 WebViewClient 并加载动态创建的 HTML 文档:

Kotlin

private var mWebView: WebView? = null

private fun doWebViewPrint() {
    // Create a WebView object specifically for printing
    val webView = WebView(activity)
    webView.webViewClient = object : WebViewClient() {

        override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest) = false

        override fun onPageFinished(view: WebView, url: String) {
            Log.i(TAG, "page finished loading $url")
            createWebPrintJob(view)
            mWebView = null
        }
    }

    // Generate an HTML document on the fly:
    val htmlDocument =
            "<html><body><h1>Test Content</h1><p>Testing, testing, testing...</p></body></html>"
    webView.loadDataWithBaseURL(null, htmlDocument, "text/HTML", "UTF-8", null)

    // Keep a reference to WebView object until you pass the PrintDocumentAdapter
    // to the PrintManager
    mWebView = webView
}

Java

private WebView mWebView;

private void doWebViewPrint() {
    // Create a WebView object specifically for printing
    WebView webView = new WebView(getActivity());
    webView.setWebViewClient(new WebViewClient() {

            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                return false;
            }

            @Override
            public void onPageFinished(WebView view, String url) {
                Log.i(TAG, "page finished loading " + url);
                createWebPrintJob(view);
                mWebView = null;
            }
    });

    // Generate an HTML document on the fly:
    String htmlDocument = "<html><body><h1>Test Content</h1><p>Testing, " +
            "testing, testing...</p></body></html>";
    webView.loadDataWithBaseURL(null, htmlDocument, "text/HTML", "UTF-8", null);

    // Keep a reference to WebView object until you pass the PrintDocumentAdapter
    // to the PrintManager
    mWebView = webView;
}

注意:请确保您的打印作业生成调用发生在您在上一节中创建的 WebViewClientonPageFinished() 方法中。如果您不等到页面加载完成后再进行操作,打印输出可能会不完整或空白,或者可能完全失败。

注意:上面的示例代码保存了 WebView 对象的一个实例,以确保在创建打印作业之前不会对其进行垃圾回收。请确保您在自己的实现中也执行相同的操作,否则打印过程可能会失败。

如果您想在页面中包含图形,请将图形文件放在项目的 assets/ 目录中,并在 loadDataWithBaseURL() 方法的第一个参数中指定基本 URL,如以下代码示例所示:

Kotlin

webView.loadDataWithBaseURL(
        "file:///android_asset/images/",
        htmlBody,
        "text/HTML",
        "UTF-8",
        null
)

Java

webView.loadDataWithBaseURL("file:///android_asset/images/", htmlBody,
        "text/HTML", "UTF-8", null);

您还可以通过将 loadDataWithBaseURL() 方法替换为 loadUrl() 来加载网页进行打印,如下所示。

Kotlin

webView.loadUrl("https://developer.android.com/about/index.html")

Java

// Print an existing web page (remember to request INTERNET permission!):
webView.loadUrl("https://developer.android.com/about/index.html");

使用 WebView 创建打印文档时,您应注意以下限制:

  • 您无法为文档添加页眉或页脚,包括页码。
  • HTML 文档的打印选项不包括打印页面范围的功能,例如:不支持打印 10 页 HTML 文档中的第 2 到 4 页。
  • 一个 WebView 实例一次只能处理一个打印作业。
  • 不支持包含 CSS 打印属性(例如横向属性)的 HTML 文档。
  • 您不能在 HTML 文档中使用 JavaScript 来触发打印。

注意:布局中包含的 WebView 对象的内容在加载文档后也可以打印。

如果您想创建更自定义的打印输出,并完全控制打印页面上的内容绘制,请跳转到下一课:打印自定义文档课程。

创建 WebView 并加载 HTML 内容后,您的应用几乎完成了其在打印过程中的部分工作。接下来的步骤是访问 PrintManager,创建打印适配器,最后创建打印作业。以下示例演示如何执行这些步骤:

Kotlin

private fun createWebPrintJob(webView: WebView) {

    // Get a PrintManager instance
    (activity?.getSystemService(Context.PRINT_SERVICE) as? PrintManager)?.let { printManager ->

        val jobName = "${getString(R.string.app_name)} Document"

        // Get a print adapter instance
        val printAdapter = webView.createPrintDocumentAdapter(jobName)

        // Create a print job with name and adapter instance
        printManager.print(
                jobName,
                printAdapter,
                PrintAttributes.Builder().build()
        ).also { printJob ->

            // Save the job object for later status checking
            printJobs += printJob
        }
    }
}

Java

private void createWebPrintJob(WebView webView) {

    // Get a PrintManager instance
    PrintManager printManager = (PrintManager) getActivity()
            .getSystemService(Context.PRINT_SERVICE);

    String jobName = getString(R.string.app_name) + " Document";

    // Get a print adapter instance
    PrintDocumentAdapter printAdapter = webView.createPrintDocumentAdapter(jobName);

    // Create a print job with name and adapter instance
    PrintJob printJob = printManager.print(jobName, printAdapter,
            new PrintAttributes.Builder().build());

    // Save the job object for later status checking
    printJobs.add(printJob);
}

此示例保存了 PrintJob 对象的一个实例以供应用使用,但这不是必需的。您的应用可以使用此对象来跟踪打印作业处理过程中的进度。当您想在应用中监控打印作业的状态(完成、失败或用户取消)时,此方法非常有用。无需创建应用内通知,因为打印框架会自动为打印作业创建系统通知。