Developing an iOS App That Prints

Some time ago, I was working on a project that required me to print some data generated by the app. I haven’t done anything before on iOS or OSX that required printing, but I was amazed about how easy it was. The OS abstracts everything very well.

I will outline some steps I take, and some tips I can share about the matter.

Initializing UIPrintInteractionController

The first step to print is initialize and display the UIPrintInteractionController. The print controller, when displaying its view, will handle displaying all the options that can be selected by the user before printing (printer selection, number of copies).

Here is the necessary code:

UIPrintInteractionController *printControler = [UIPrintInteractionController sharedPrintController];

Optional

You can also set a class to respond to delegated callbacks from the print controller.

[printControler setDelegate:self];

Add UIPrintInteractionControllerDelegate protocol to the header file (.h) to make the compiler happy.

@interface MyController : UIViewController <UIPrintInteractionControllerDelegate>

That way you can respond when the application started printing, finishing print, etc. Creating a UIPrintInfo

UIPrintInfo is an object we can optionally create and pass it to the UIPrintController to provide some information about the job we will be printing. Here is an example of how you may use:

UIPrintInfo *printInfo = [UIPrintInfo printInfo];
[printInfo setOutputType:UIPrintInfoOutputGrayscale];
[printInfo setJobName:@"My Pretty Paper"];

And you can pass it to the controller by doing

[printControler setPrintInfo:printInfo];

Note that I’m setting the output type to UIPrintInfoOutputGrayscale, this just means that whatever I’m printing is just gray scale content, so I’m not wasting the user printer colors when I don’t needed. You can pass different values to that.

Formatting Content

I found that the best way to print a custom-generated content from an app is by building an HTML document of it. HTML is pretty easy, and most developers have at least a basic understanding of it. Also, it can be easily tested outside the app, and you could even include templates .html files as a resource in your app. The easiest way to do it is by simply generating a string, where its content is an HTML document.

Let’s create an NSString so we can print it:

NSString *myPaper = @"<!DOCTYPE html>"
    "<html>"
    "<body>"
    "<h1>Print me!</h1>"
    "</body>"
    "</html>";

Now, we need to create a UIMarkupTextPrintFormatter object. We do that by calling the initWithMarkupText: method, and passing our myPaper string.

UIMarkupTextPrintFormatter *htmlFormatter = [[UIMarkupTextPrintFormatter alloc] initWithMarkupText:myPaper];

Let’s do some additional setup to make it look good by setting the page insets and from which page we want to start printing:

[htmlFormatter setStartPage:0];
[htmlFormatter setContentInsets:UIEdgeInsetsMake(72.0, 72.0, 72.0, 72.0)];

Now let’s pass our htmlFormatter, that contains our content, to the printController:

[printControler setPrintFormatter:htmlFormatter];

HTMLEncoder

HTMLEncoder is a small library I created to help generate HTML like content. I never liked concatenating and manipulating huge strings. It abstracts everything from HTML and let you do what you have to do only using Objective-C objects.

You can visit HTMLEncoder GitHub page to see an example, or download it.

Print!

We are almost done! We did all the setup necessary, now we just need to make it print. We don’t actually call anything to print. We simply present the printController we created and configured, and the OS will handle the rest. There are different ways on which you can present another UIViewController. Here is one way that it can be done:

[printController presentAnimated:YES completionHandler:
    ^(UIPrintInteractionController *printInteractionController,
      BOOL completed,
      NSError *error) {

    if (!completed || error) {
        NSLog(@"Printing could not complete because of error: %@", 
                                      error.localizedDescription);
    }

}];

In the code above, I’m asking the printController to present itself, animated, and I’m also passing as the third argument a code block that will be called once print job is done. You could also be using the UIPrintInteractionControllerDelegate methods to be notified when a job is done. Usually on my app it just matters for me to know when the print job failed, so I’d rather use blocks in that case (I avoid blocks if they end up being anything bigger than a few lines).

Inside the code block, I’m just checking if the completed flag is NO (false), or if the error object is not nil (NULL). In case any of those conditions are true, you could handle the error. In the example above, I’m not doing anything other that printing the error description to the log console.

Happy printing!