The latest version of Android, KitKat, adds long-awaited printing support to the platform. Android applications can now provide low-level control of print jobs, in addition to print integration for applications incorporating web content. This makes KitKat particularly well-suited to hybrid applications built with Xamarin using Razor templates.
Printing with a WebView
First let’s look at the easy to use print support offered through the WebView control.
Printing requires 3 steps:
- In an Activity, get a reference to the PrintManager system service.
- Create an instance of a class that inherits from PrintDocumentAdapter.
- Call the PrintManager‘s Print method, passing it the print adapter.
The PrintDocumentAdapter is an abstract class that provides a contract to implement for supplying print content. For web content, the WebView class includes a PrintDocumentAdapter, making printing HTML from a WebView incredibly easy to do:
The following example shows a WebView built using the Android WebView template, which uses Razor as an HTML templating engine:
Although printing can be done using any WebView, integrating printing with Razor and this project template makes it really easy to build a hybrid application that can leverage native features such as KitKat printing.
Printing from the WebView with C# is as simple as adding these 2 lines of code in the activity:
var printMgr = (PrintManager)GetSystemService(Context.PrintService); printMgr.Print("Razor HMTL Hybrid", webView.CreatePrintDocumentAdapter(), null);
When we call Print Android presents a system dialog, allowing the user to choose the print destination, as shown below:
Custom Print Adapter
To print from native Android views, taking low-level control of the print layout, we can implement our own PrintDocumentAdapter.
For example, let’s say we would like to print the layout from the following screen:
In our implementation of PrintDocumentAdapter, the required methods to implement are:
- OnLayout – Allows laying out print content based on the PrintAttributes.
- OnWrite – Allows writing a PDF file with content to print.
In OnLayout, we create a PrintDocumentInfo instance, which contains metadata about the document being printed.
public override void OnLayout (PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras) { document = new PrintedPdfDocument (context, newAttributes); CalculateScale (newAttributes); var printInfo = new PrintDocumentInfo .Builder ("MyPrint.pdf") .SetContentType (PrintContentType.Document) .SetPageCount (1) .Build (); callback.OnLayoutFinished (printInfo, true); }
In OnWrite, we implement the code to draw printed content and write it to the output stream to be printed.
public override void OnWrite (PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback) { PrintedPdfDocument.Page page = document.StartPage (0); page.Canvas.Scale (scale, scale); view.Draw (page.Canvas); document.FinishPage (page); WritePrintedPdfDoc (destination); document.Close (); document.Dispose (); callback.OnWriteFinished (pages); }
Printing with our custom adapter is just like using the WebView‘s adapter. Simply pass an instance of the custom adapter, called GenericPrintAdapter in this case, to the PrintManager‘s Print method:
var printManager = (PrintManager)GetSystemService (Context.PrintService); var content = FindViewById<LinearLayout> (Resource.Id.linearLayout1); var printAdapter = new GenericPrintAdapter (this, content); printManager.Print ("MyPrintJob", printAdapter, null);
When the user clicks print, the same system dialog is displayed. In addition to a local printer, you can select Google Cloud Print or print to a PDF file, resulting in the print shown below:
The printing support added to KitKat is a much welcome feature that is easy to get started with. You can download the code used in this post from my GitHub repo.
0 comments