Core OS • iOS, OS X • 49:19
AirPrint is widely supported by all the well-known printer companies. Learn how quick and easy it is to support AirPrint in your app. Discover what's new and improved in the iOS printing system.
Speakers: Charles Duyk, Howard Miller, Todd Ritland, Claudia Roberts
Unlisted on Apple Developer site
Downloads from Apple
Transcript
This transcript has potential transcription errors. We are working on an improved version.
Okay, good morning, everybody. Welcome to the WWDC 2014 Printing session. I'm Howard Miller, I'm the Engineering Manager for everything printing at Apple. Today we've got a pretty straightforward agenda, we're going to give a little bit of an update on AirPrint. We're going to spend the majority of our session on iOS printing.
We're going to show you the new iOS printing technology that's in iOS 8 and we're going to give you a demo of that. So I know everybody probably went to the parties last night, so we've got to wake everybody up. How many people here have applications that already print? All right, we've got a good number. How many here have applications that you want to have print? All right. By the time you guys leave today, your applications will be able to print.
I know you can write the code while sitting right there because it's going to be that easy. But if you don't get it done, we have a lab that follows this, you can come down, and we will get your code printing today. So let me give you an update about AirPrint. What is AirPrint? You know this technology was released with iOS 4.2 several years ago, and our primary goal was to provide a great, outstanding user experience.
Printing was a pain, really was painful. And we worked on the Mac to make it simpler but it still wasn't super simple. And we got to iOS. We had to have no drivers, no software to install, no configuration. The user just wants to put their printer, connect it to the network and then when they go to print, there's their printer and they print.
You don't need 50 million options. The printer should be smarter. The printing system should be smarter. And that's what we did. But we didn't sacrifice output quality. With AirPrint you get the full print quality that Apple's become known to deliver for the last couple decades. It is as good or in some cases better than what you can get from the desktop. No compromises were made.
Your printer manufacturer? AirPrint's a protocol, standards-based, plus a little Apple secret sauce on the side. And if you're a technology provider, a server vendor, we will license you all this technology at zero cost. Printers, you know we introduced with a dozen or so printers from HP. I'm proud to report that we have 100 times as many printers now. If you go into any Staples or Fry's or pick your favorite electronic store, virtually every network printer they sell now has AirPrint in it. By my read, about half of the world's installed base of printers have AirPrint in it.
You almost cannot find a printer that your mom would want that doesn't have AirPrint. Last year, all the enterprise vendors came on. Kyocera, Sharp, Toshiba all have AirPrint throughout their product line. As I mentioned, AirPrint is available as a printing system in iOS 4.2 and later. For those who have done the math, that means there are more than 700 million users that have the same printing system on it. That's more than any other printing system in the history of the computing industry. So AirPrint's printing system is the most prevalent printing platform out there. Then, of course, the most important thing is your app.
And you just got to believe this, the Microsoft guys released a beautiful product, they left one small feature out. And they heard about it right away on day one. And by the end of that week I was on the phone with their engineers telling them to check out the last WWDC presentation. And within a couple days, their app was then printing. Of course, it took them the better part of a month to release it.
We're going to get you out of that. What you need to know about AirPrint is it's super, super easy. The user interface is easy. The user interaction is easy. But equally important, and probably more important for you, is that the API set that we have is not some random walk through 100 different things.
We have a very, very focused set of APIs that are very efficient to get you right down to what you need to know. And with little work and a little help from your application, print system's smart enough to know what to do with your output, and we can get super high-quality output without having to have a bunch of user interaction.
So let's talk about what's gone on with AirPrint. We started with consumer ink jets, we got consumer laser, we've got enterprise lasers, we've got some servers. Last year we talked about Brothers first roll-fed printer. And as things go there are always new classes of printers coming. And we're getting into some of the specialty printers. So we're going to start with one of my new favorites. This is probably not what your mom's going to get at home.
This is the AstroMed ToughWriter 5. The reason I like this is because its native spot is on the cockpit of an airplane. There it is, set in its native 747 environment. But this will end up in C-17s with the military, will end up in commercial. But what's interesting is iPads and iPhones are everyplace.
Applications need to print. And the printer manufacturers of all types are responding. This is a curiosity and there probably won't be millions of these printers sold, but it shows that AirPrint is pretty much every corner of the world now. Another printer that I'm really happy to talk about is the Brother RuggedJet 4040. This is a very small battery-powered receipt and label printer. It will support AirPrint soon. And we'll have a demo of that later today.
So let's talk about what we've added. We have added some new APIs in iOS 8. These are to support specialty printers and applications. If you look at what we did in AirPrint so far, every time you print, the user has to see our print dialog, which means they get to pick a printer. Now, if you're doing an application for the Lucky's store checkout counter, you certainly don't want the clerk everyday picking their printer every time they print every receipt for the customer.
If you're at Lucky's, at least my Lucky's, they have two printers there. One printer prints the receipt, the other one prints those coupons, and they tear them off and they give you both. This set of APIs will allow you to have multiple sets of printers preconfigured by an administrator that at runtime, the user, the application can select which printer without the user having to get involved.
So we'll have a bunch to talk about that in a minute. So let's talk about some hints. First off, everybody's designing their applications for the screen. We've got some beautiful iPads with Retina displays. But for those of us in the printing world, that's pretty low-resolution output. It's also output that is backlit.
When we start talking about paper, you have a much larger canvas, a much larger space to utilize. And that means that you want to lay out your stuff to make effective use of the space. You want to provide higher quality graphics. You're going to need higher resolution graphics than what you're showing on screen if you want the output to be truly spectacular. Then I want you to think about readability. You know, they don't print books that people are going to sit on their couch and read with no margins. There's always a big margin so your big, fat thumb can be there and you can still read the words.
Consider what paper is. It's going to be reflective, light's going to come off of it. Gray looks awesome on screen, gray looks awful when it comes to print, it's hard to read. Consider the contrast, consider the margin, consider the fonts, consider the spacing. Paper's a little different than screen, and with just a little bit of forethought, you can get spectacular printed output.
With respect to the printing system, it's a smart printing system. We do a huge amount of stuff to help your app. If you tell us that it's a photo, for example, we will automatically pick the photo tray, pick photo print mode, pick the highest quality print mode, scale the item to fit on the page centered and print.
You're going to tell us what you're trying to print, we're going to work all the magic behind the scenes in the printing system to make sure the user gets the best output. Okay, there are a few data objects that we're going to hand you, you're going to hand us back. And I just you know the caveat, don't troll around in those and try and tweak stuff, don't introspect these opaque objects, we may change something, in fact we probably will, and I don't want to break your app in the future.
And then the last thing, if there's anybody here who tests their app - does anybody tests their app? Okay, at least a few of you do. You don't have to go buy all 1,200 AirPrint printer models that are available in the world. Go back to the 2012 WWDC session.
We spent about 15 minutes on something called the Printer Simulator, which is part of your Xcode release. It allows you to simulate every common type of printer, including changing some of their parameters. So ink jet printers, laser printers, roll-fed printers, you don't have to buy them all. Buy one and use the printer simulator to do your work.
Okay, let's get to the focus of today's meeting. Again, our goal is by the time you leave here today, you can create an app that prints. And for the meat of this presentation, I am going to bring up one of my engineers, Todd Ritland, and he is going to take you through everything you need to know to make your app print.
[ Applause ]
Thanks, Howard. I'm Todd Ritland, I'm an AirPrint Engineer. I'm the lead on the iOS printing system. So we're going to talk about iOS printing here. First we'll talk about picking what to print. Next we'll go over the APIs and how to actually get output. Then we'll talk about some of the different printing UI options. So first, this is our motto, I think we've made this clear, but iOS printing is easy but powerful. We designed the AirPrint protocol to scale from, you know, small consumer printers all the way up to big enterprise-class printers, and everything in-between.
And with every iOS release, we've been adding and expanding the types of things you can do from iOS. But we kept it real easy; so we want the user interaction to be really, really simple and basic. We haven't added and added and added, and really try to keep feature creep down.
So providing good content for printing, this is really the most important part. What we're looking for is printed output that's useful, attractive and high quality. We like to think of this like high-end graphic design. It's best to design your output like a graphic designer would, and then use our classes to make that happen instead of approaching it the other way around, where you're just looking at all the classes and kind of tweaking what you want to do. First, design it and then use our classes. As Howard said, what looks good onscreen doesn't always look good on paper.
We also want you to make use of the dynamic printing system. So paper size can be anything, and we actually talk to the AirPrint printer, we figure out what size papers are available. Some printers actually have paper size sensors that can tell what papers in it or the user can enter it on the front panel what paper is loaded.
And so the printing system was designed to be dynamic, it sends that all the way up to your app. If your app is dynamic about its content, laying it out, then you get the full benefit of that. Printer hardware margins also vary quite a bit. Sometimes the bottom margin might be large. The margins on other sides might be really, really small.
So for all these reasons, it's really best not to produce a thick-size PDF and send it to the printing system. Also, another thing to keep in mind is, there's really two major document sizes for paper in the world, U.S. letter, which is what we use in the U.S., and then there's A4 which is used in a lot of other regions in the world.
So if you design your output based only on the paper size that your region uses, you might be missing out on a whole other market, so it's good to think about all these different paper sizes. And like we said, the printing simulator you can use to simulate these different conditions.
So a good example of printing is this math dictionary for kids. This is an app that lets you look at different definitions of math terms. In this case, we're looking at the laws of arithmetic. And if you were a teacher and you wanted to make like a handout of this, you can print it out and this is the output you'd get. It looks really nice.
This would be suitable to hand out to all the students in a classroom. It has a nice header and footer. There's the page number at the bottom. The examples are in nice callout boxes that are a different color. And this output would actually even look really good on a black and white printer.
And if whoever was printing had U.S. legal loaded in their printer, and the printer reported that back to the printing system, this app is dynamic and it fits all the content on one page, it stretches it out, it looks good. So this is a good example of being dynamic about the content.
Okay, so let's step right into the APIs here. The basic steps of printing with a UI, this is standard printing, first your app will get the print controller or the activity controller, the share sheet. You'll set up the attributes for the job, like job name and the type of job. Then you'll provide the content for printing, and we'll go over that later. And then you'll present the UI.
At this point iOS takes over, it communicates with the AirPrint printer, figures out all the relevant information. The Daemon takes over managing the job. If the job needs a username and password, the printing system takes care of that. If paper runs out or ink runs out, any of that kind of stuff, that's all managed by the Daemon.
So your app doesn't need to deal with any of that stuff. So here's the classes we're going to be focusing on. First, UIPrintInfo, just the general sort of metadata about the print job, the job name, and the type of job. UIPrintPaper which just represents the sheet of paper at the printer.
A PrintFormatter which knows how to format content for a sheet. UIPrintPageRenderer which lets you take full control over drawing. Then for showing UI and managing the job, we have UIPrintInteractionController, or UIActivityViewController which is the share sheet. So first let's go over UIPrintInfo. Every print job should have a UIPrintInfo set up for it.
First thing you'll do is set the job name. Now, this job name appears on the front panel when the user prints to printer - when the user prints their job. But also appears in print center, if the user wants to cancel their job. If they're printing to a server, for like a print and release server, this is how user's going to be identifying their job. So it needs to be really specific. If it's something generic like just "print job", that doesn't really help users identify which job is theirs. So it's really important to make sure this is as specific as possible.
Next we have output type. This just tells the printing system about the type of content that you're printing. It allows the printing system to make appropriate choices for paper size, the print quality mode, and we also make UI decisions about what to show for the UI based on output type. We have four of these. First one, just a general UIPrintInfoOutputGeneral. This is like, you know, mixed text and graphics, like a webpage that we're showing here.
We'll tell the printer to print at normal quality, so it's not going to do high quality and take a really long time. It'll by default choose a document paper size, so like A4 or letter. The UI allows duplex to be shown and page range too. Next one we have is document grayscale. This is very similar to the previous one, but this is optimized for monochrome like text and monochrome graphics. In this case, you'll get improved print speed because we can tell the printer this is just black and white. The data over the network can be less.
It will in many cases reduce the amount of ink that gets used because the printer will go into a black-only mode. And like the previous example, duplex allowed and page range controls will be allowed in the UI. The next one is photo. Like Howard mentioned, you can tell us you're printing a photo.
We'll choose high quality, we'll tell the printer, this is a photo, print it at highest quality. We'll choose a photo paper size based on the region. If the printer allows borderless printing, we'll choose borderless printing. And because duplex and page range don't make sense for a photo, we don't show those in UI. So you get a really, really simple UI.
And then similarly, we have high quality grayscale photo, which is in most ways it's the same as the previous one. But some printers have a high-quality grayscale mode. Some have gray inks and can print a photo in grayscale really, really nicely. So we'll tell the printer to do that. So choose this if you want your photo to come out in a really high-end grayscale way.
Okay, so that's UIPrintInfo. Next we'll talk about UIPrintPaper. This is a really simple class, it just basically has a paperRect that represents the full sheet of paper, at (0,0), and just the rectangle is the size of the sheet. Then inside of that we have the printableRect, this is the imageable area. It's where the printer can actually image content. So it's basically the full page minus the hardware margins.
Okay, next we'll talk about providing content, so this is really the meat of the presentation here. There's three levels here. We have the easiest way, then there's a little bit more it's still simple but a little bit more involved, and then the fully custom drawn pages. So first, the easy is PDF files, image files, things that are already basically ready to print.
To print these, it could be a single item or it can be an array of items, like if you have a bunch of photos you wanted to print, you could provide an array. It could be, like I said, PDFs, JPEGs, any image type that iOS understands. It can be in the form of an NSURL to like a file on disk, or they could be in memory in the form of an NSData, UIImage, CIImage. It can even be something in the photo library like an ALAsset or an ALAssetURL, and the printing system knows how to go into the photo library and grab that. If you provide an array of items, each one of those items will be a separate job.
So here's all the code that it would take to print a PDF file. It's pretty simple. This method just takes in the URL to a PDF file on disk. First we ask the UIPrintInteractionController if it can print this URL. Some examples of when it wouldn't be able to print it are if the PDF was password-protected or if it was malformed in some way. Next we grab the UIPrintInteractionControllers. It's a shared object, so we just grab the sharedPrintController. We set the printing item property to be this URL to our PDF. If it was an array of items, there's a different property called printingItems that you'd set to be the array.
And then we set up our UIPrintInfo, like I said, we'll do this for every job. We'll set the output type to be UIPrintInfoOutputGeneral, because PDFs typically have mixed text and graphics. The job name will be just the filename of the PDF. And then we'll set the print info property of the UIPrintInteractionController to be the print info that we just created.
Next we'll set the show as page range property to be yes. By default it's no, but for a PDF, usually users are going to want to be able to specify page range within the PDF to print. And then we'll just call presentAnimated:YES completionHandler with no completion handler. And at this point iOS takes over, you don't have to do anything else in your app. Like I said, if there's issues, you know, like out of paper, any of that kind of stuff, that's all managed by the system, you don't have to handle any of those errors or anything.
Okay, so that's the easy level. Next is basic: printing simple content. If you have just text or if you've written your whole print layout in HTML, you'll just use one of these provided formatter classes. So formatters is what we'll be using. Now, what is a formatter? It's pretty basic, it just basically takes in the abstract sense, it takes some data in your app and some rectangle on the outputted sheet of paper, and it knows how to format it. So it's pretty basic.
So in this case, like a string of texts, say we have the Gettysburg Address in an NSString, we can use a UISimpleTextFormatter and it knows how to take that string and to lay it out onto a page into this rectangle. Now, the whole string doesn't fit on this one page, so formatter knows to just keep going until all the content - all the data gets used up.
So you can use formatters directly with UIPrinterInteractionController or the UIActivityController, the share sheet to format for a whole page. You can also use formatters as a helper and a full renderer, and we'll talk about that later. For plain text, use this UISimpleTextFormatter. This allows you to specify font, color, alignment, you know, kind of control the text, how you want it to look on the page. For HTML markup, you'll use the UIMarkupTextFormatter. And it knows how to format, you know, based on HTML rules, using WebKit.
So the layout, by default, here's our paper, like we shared before, by default it uses the printableRect, which is the imageable area. But that might be really, really close to the edge of the page. Some printers, you know, only have like 1/10 of an inch on the edge that they can't print. So like Howard mentioned, that's not a good thing. We don't want our content to be that close to the edge of the page.
So we've provided a property on the formatter that you can use. And new this year, we have perPageContentInsets. This lets you specify left, top, right and bottom on every page. So it'll keep going until all the content's used up and it'll honor those margins on every single page. Previously we had a content inset, which has behaved a little bit differently, and we think this is a little better, it'll allow you to get nice top and bottom margins that are consistent on every single page.
So here's a quick code sample of using a formatter. And this is all the code you would need if you had your print layout design in HTML, this is really all you'd need to do is this method here. And so the method takes the HTML text as a parameter. We create our UIMarkupTextFormatter, initialize it with the text that was passed in. Next we set up our per page content insets, which is a UIEdgeInset. So we'll call UIEdgeInsetsMake. We'll put 3/4 inch top left, bottom and right.
And then we'll just set the print formatter property on the controller to be the formatter we just created. Then we'll set up our UIPrintInfo like we always do. We'll just set output general. The job name will be the webpage's URL field. And you present. So that's all that you need to do.
Now, view formatters, every view in iOS has a print formatter that knows how to get the content in the view onto the page. iOS wasn't really designed to be view-based printing though, but some views are really useful for this. So this example, a map view, if you want to get that content, the map that's in a map view, all you need to do is call the ViewPrintFormatter on your map view, and then you can add this right to your print controller and print with it.
Another view that's really useful to use the view print formatter is a web view. If you have a web view in your app and you want to get that content to print, all you need to call is the ViewPrintFormatter. So you don't need to initialize it on your own, you just grab it from the view.
Okay, so that's our print formatters. So that's the intermediate level, the basic level. Next is, you know, a little bit more advanced, it's fully custom drawn pages. This is for if you want to really take total control over the drawing. And we'll be rendering the pages with content using renders mostly but you can also use the formatters, like we just went over, in renderer.
So renders, what is a renderer? Well, here's our renderer object and it's really responsible for at least two things. First of which is responding to number of pages, so it has to know how many pages total is going to be printing. In this case, two, it responds two. The next thing it has to do is when it's called drawContentFor PageAtIndex:inRect. So the printing system tells it draw the first page.
And it gets to use any drawing methods that are at its disposal. So any screen drawing methods, Core graphics, Core texts, UIKit drawing methods. And then it's told, draw the second page, because we said two pages, and so it just gets to do however it wants to draw. So this is what you'd do for, you know, elaborate printed output.
So you'll subclass UIPrintPageRenderer. And like I said, at a minimum you'll override number of pages, and drawContentForPageAtIndex. It also has a few other methods you can override, like draw header, draw footer, things like that, and those are documented. You'll set the UIPrintInteraction Controllers printPageRenderer property to be your instantiated object or your custom UIPrintPageRenderer class. Or you can add that object to the array of activity items, if you're using a share sheet.
You can also add formatters by calling addPrintFormatter: startingAtPageIndex, because a print formatter can start at any page. Now, how would you use a formatter with a renderer? Kind of maybe a little bit complicated to think about, but it's really pretty basic. So here's our renderer, and when it's told to draw page, all it's doing is it's going to draw some flourishes on the top and the bottom. But in the middle we want to draw text. So the renderer has a UISimpleTextFormatter. Here's our rectangle that we've set up where we want that text to go.
And our Gettysburg Address again. The UISimpleTextFormatter just formats it in the middle. So if you want to use formatter to, you know, do HTML on a part of your page but then you want full control over drawing the rest of it, you can do that. Okay, so showing the UI, there's a couple different options. Printing from the share sheet is probably where most people expect printing if it's sharing some general content and printing is one of the options. This is where printing appears in most of the built-in apps in iOS, like here in Safari.
To do that is really basic, we'll just, when we set up our activityItems, we'll just add a printInfo which has job name and job type and all that, you can add then a renderer like this case. And for this example we're like sharing a webpage, and most the time when you share a webpage you're sharing the actual URL. But in the case of printing, you want to actually render out the whole web page. So that's what this example's showing.
Now we'll just initialize our UIActivityViewController with activity items that we just created, and nil application activities. So printing is always an activity item, not an application activity. And then we'll just present using the standard view controller present methods. So in the other case, printing with like a Print button, you'll create and set up the UIPrintInteractionController, like we did in our examples. For a standard presentation, you'll call presentAnimated CompletionHandler. And for a popover presentation, presentFromRect inView or presentFromBarButton item, animated completionHandler.
So now printing as a menu item, if you want to embed the printing UI in your own UI, like in this case's pages where you select the Print button and it slides over and gets pushed into it like a NAV controller. You'll set your class as a delegate for the shared UI printInteractionController. You'll implement printInteractionController ParentViewController. So you'll tell the printInteractionController which view should be apparent.
Then when the user taps print in your UI, you'll just call presentAnimated: CompletionHandler on the UIPrintInteractionController. And then if your class that you've told it is the parent is a UINavigationController, it'll get a push. And if it's some other UIViewController, it'll just get a modal presentation. But really the NavigationController is where this is most useful.
Now, controlling paper size, if your app is designed with specific paper size in mind, like a document center gap, like pages where the user's actually laying out their content, your app will have to provide its own paper selection UI. This is the example for pages here where you get to choose a couple different paper sizes. Then you'll use the delegate method printInteraction Controller:choosePaper. This is called after the user selects a printer. We've communicated with the printer. We figured out the papers that are available.
And you then will ask for a paper size that's a good match to the one that the user selected. If the printer has paper sensors or if the user inputted exactly what paper they're loading, the array that gets returned will only be the ones that are detected, because those are the only options available.
So here's a quick example of our delegate method for choosePaper. In this case we're looking for 8 1/2 by 11 sheet of paper, so we'll just create a CGSize pageSize. And then we'll use UIPrintPaper bestPaperForPageSize withPapersFromArray method. So we've provided this method for you on UIPrintPaper because it's actually pretty complicated to match for a target paper size from a list of papers, it's kind of complicated and we've made it easy for you.
So we just recommend that you just call this. Next up is roll paper. This was new in iOS 7. It's similar to choose paper in that you can have a delegate method called cutLengthForPaper. This method will only be called after the user selects a printer that actually has a roll loaded in it.
It'll have a UIPrintPaper passed into it with the width of the roll, and the height of the paper will be the maximum height that the printer allows. By default, if you don't have this delegate method, which most apps won't, and if the user chooses a printer that has a roll loaded, the cut length will just be proportional to whatever default paper would be used for that job. Okay, next up this is the new thing in iOS 8 that we're very happy to announce is printing without showing UI.
Now this opens up the opportunity for new types of printing applications, so we're really excited about that. WWDC this year is all about enabling developers to do new, interesting things that you weren't able to do before. So we're excited to have this. But what this is not for is for apps that provide their own custom print panel. It wasn't designed for that, and in some ways you're not going to be able to do that.
So here's our standard printing UI, let's just break it down into some steps. First what the user uses this UI to do is to select their printer, then they set some options like copies or duplex, things like that. And then they tap Print when they actually want to print. So what we've really done is separated this out into two things.
The user's still going to need to select a printer, but that's done up front. And so for that we have a printer picker. And then to replace the settings that they would be using, we have App Controlled Settings in API. And then we have a new print method on UIPrintInteractionController that you'll be calling. So it's kind of separated into two things, initial setup and then when you actually print.
So the basic steps for printing without a UI, first your app will include a setting for setting the printer, this is in the app setting somewhere or in a settings button somewhere. So to do that you'll first get the printer selector, this new class. You'll present that UI.
Then you'll save the printer chosen by the user. So the user will be choosing a printer. It's the app's responsibility to save that. Then whenever appropriate, when your app decides to print, the app will then get the print controller, the UIPrintInteractionController. It'll set up the attributes for the job and provide content, just like we did before. Then they'll send the job with this new print controller method that just sends without showing UI. At this point, like before, iOS communicates with the printer, the Daemon takes over, your app doesn't have to deal with any of that.
So here's the classes we'll be using for background printing. First, the new class, UIPrinterPickerController, that you'll be presenting. Then a UIPrinter object that your app will be saving or instantiating between runs, and providing that to the UIPrintInteractionController. So everything that we've talked about with the UIPrinterInteractionController still applies. So your app is required to use this UIPrinterPickerController to pick the printer.
It's complicated to show all the different printers and sometimes, you know, your users need to unlock a printer if it has a username and password, all that kind of stuff is handled by the system. So you'll use the UIPrinterPickerController. It has the same presentation options as the print interaction controller. So you can present it as a popover or a sheet or you can embed it in a NAV controller.
Then, like I said, your app will be responsible for saving that printer. Between runs you'll save the URL, and then you'll instantiate a new UIPrinter with just this URL that you've saved. Also, this UIPrinterPickerController allows you to filter out printers if your app is designed for just a specific type of printer, and we'll talk about that later.
So like I said, you'll create and set up the UIPrinterPickerController, you can present with standard presentation, presentAnimated, or pop-over presentation with presentFromRect or presentFromBarButton Item. The completion handler though for these methods will tell you whether the user actually did select a printer. If they didn't, you know, they could've just cancel it, so then it'll say that they didn't select a printer. But then your app is responsible for saving that printer that was selected.
So when your app is ready to print then, at the appropriate moment, you'll use the UIPrinterInteractionController and you'll call the new method printToPrinter with this UIPrinter object completion handler. The UIPrinter passed in, like I said, can be obtained from the UIPrinterPickerController directly or you could have instantiated it with the saved URL.
Okay, so that's UIPrinterPickerController. UIPrinter, new class in iOS 8, first it has a contactPrinter method. So this is used if you're instantiating it, you want to make sure this printer is there, and to fill out the rest of the properties for the printer, you have to contact it. You'll pass in a block that's a result block that will tell you whether the printer's available or not, it might not be on anymore, so it'll return no in that case.
Next is the URL which is a read-only property. This is what you'll be saving out once you get your initial UIPrinter, you'll be saving this. Next we have displayName, which this is our standard printing UI, the displayName is, you know, this, the name of the printer, it's appropriate for you to show in your UI.
displayLocation which is the smaller text underneath the name. You can use this for display in your UI as well. And then some various things about the printer, like supportedJobTypes, which is a bit field. It'll say like whether it supports photo printing or receipt printing or envelope printing, different types of jobs it supports, and makeAndModel and some other capabilities. So here's a quick code example of using UIPrinter to show like the printer name and the location in your UI. So first let's grab the savedPrinterURL from a previous run of the application. Here we're just getting it from the UserDefaults.
If we got one back from UserDefaults, we'll initialize with UIPrinter printerWithURL with the savedPrinterURL. And then it'll actually contact the printer. The block that we will pass in we'll see if it's available, then we'll set our printer name label to be the display name of the printer, and the printer location label to be the display location.
So the printer name and location aren't available until it's actually been contacted, so that's why we do that in this block. If the printer's not available, we'll have some ConnectionGoneIndicator in our app. If you want to have this, this is how you do it. So if it was like a little red indicator to tell users that their printer's not available, this is how you'd do that.
Okay, so like I said, you can use - you can filter out printers in the printer picker. For that, this is, you know, for apps designed with specific printers in mind, if you really only want your app to be used with receipt printers or with, you know, specific type of printer, this is what you'd do. Any one of those properties on the UIPrinter you can use to filter. When you present the UIPrinterPickerController, you'll just use the delegate method, shouldShowPrinter.
You'll return yes or no whether it should be shown. So this is called for every printer as it gets discovered, and you can choose whether it gets shown in UI or not. So we're really excited about this. We really do think this will enable a new class of printing applications that weren't possible. And to talk about some of those new types of apps, I'd like to bring up Claudia Roberts, our Printing System Engineer.
[ Applause ]
Hello, everyone. My name is Claudia Roberts and this is my colleague, Charles Duyk. The exciting thing about UI-less printing is that it opens up the door to a wide range of printing applications. One of our most requested features for iOS 8 was to allow apps the ability to print receipts without showing the print dialog. In a few minutes, Charles will demonstrate how to do just that, using a cash register app.
But we encourage you to think more broadly. Think of a photo booth app that automatically prints out your burst of photos. Or a label printout to be used at conference sign-in tables. The fact that we're letting you save printers means that you can now preconfigure an app to print to more than one printer.
This is a great feature that can be used when setting up multiple printers where each might serve a different function. Think airline kiosk app. The person traveling checks in, enters the number of bags they're traveling with, and after finalizing their information, one designated printer prints out their baggage labels and another prints out their boarding pass, all without ever having to traverse or even see the print UI.
Today to illustrate the power of this new feature, and to demonstrate just how easy it is to add UI list printing to your app, we've created a hypothetical cash register app. A cash register app is something you'd find in most any retail store. In using the printing paradigm in iOS 7, printing a receipt used to mean a lot of unnecessary interaction with the print UI. And there was really no way of getting around this.
After finalizing a sale in this demo app, it takes 1, 2, 3 steps to print out a receipt each time the clerk goes to finish the sale. Add a queue of 5 to 6 people, and you have yourself a less than ideal situation. So what do we know to be true? For the most part, in a given day at the shop, the clerk will almost always print to the same receipt printer.
Thus, this leads to our desired behavior, the ability to simply tap on the Finish Sale button and have our dedicated receipt printer print out the receipt so that a customer can quickly be on his or her way. I will now hand it over to Charles who will demonstrate how to update this cash register app with the necessary code changes to achieve the desired behavior.
Thanks, Claudia. So what I have here is the code for the cash register app that Claudia just showed you. And I want to update this to use these new APIs. So like Todd said, there's really two basic steps to printing without the UI. The first is selecting and saving a printer, and the second is telling iOS which printer we'd like to save to. So in order to do this, I'm first going to want to create a place to save the UIPrinter object that I'm going to get.
I'm going to add a property here to my ReceiptViewController, using the new UIPrinter class. This is what iOS uses to represent the printer throughout the printing system. Next I'm going to add a place where an administrator can go and set up the cash register in order to let the app know this is the printer I'm going to be printing to. So we'll do that in the Settings button. So I'm going to go to my settingsButtonPressed method, which is a - sorry, which is the target action of a Settings button in the app. And I'm going to go ahead and create a UIPrinterPickerController.
We'll create the UIPrinterPickerController using printerPickerController WithInitiallySelectedPrinter, to scroll the controller to maybe a printer that we've already set up. Next I'm going to use the UIPrinterPickerController method presentFromRect inView animated in completionHandler. And when the user goes and selects a printer, we'll go ahead and check to see that they did select it, and if they didn't cancel the operation, save the printer that they selected in the property that we just created. Now I'm going to go ahead and update my app to use these new APIs.
So here you can see our print method as it exists in iOS 7. We do all the standard printing things, we create a PrintPageRenderer, we create a UIPrintInfo, set some job options, and get the sharedPrintController, set the options on the job, and then present it using the present APIs, which you'll notice, look almost exactly the same as the methods on UIPrinterPickerController. So what we can actually do now, and this is what's kind of neat about this API, is delete some of this code, because we don't need it, we're no longer presenting anything, we're just going to print to printer. There we go.
Then we can go ahead and delete that little bit of auto-generated code. And it's really just that easy. All of a sudden, the completion handler's the same and we're now going to be able to print without the UI. So I'm going to go ahead and fire up the simulator here so we can show this to you.
And something that I didn't get a chance to talk about here but that could be a logical extension is maybe filtering based on the type of printer that we're going to use. We want to use only receipt printers with this app. But, you know, maybe your shop also has a photo printer and you wouldn't want to print to that - or you wouldn't want to show that to the administrator when they were setting up the printer. All right, so now we have our app. And let's go ahead, let's say maybe we're in a coffee shop. So let's get, you know, the San Francisco coffee and, you know, maybe a bagel.
Yeah, okay, why not. All right, so that looks good, you know, we're splurging on the bagel, so maybe we won't get cream cheese. So let's go ahead and say finish sale. Oops, I didn't select a printer. So let's go ahead and look for this. Notice we're going to pick this Brother printer that we have here, it's a Wi-Fi-enabled, battery-powered receipt printer.
Now we'll go ahead and click Finish Sale. And now iOS will take over the job communicating with the printer, you know, getting all the options, et cetera. And in a moment should be seeing the paper come out of the printer. And with that, I will hand it back to Howard who will take us out.
Today, what I hope you have learned is adding printing to your application regardless of style of application is really easy. For a lot of the content, 10 lines of code. If you have pictures, HTML, web views, maps, you're set. 10 lines of code, it's really 9 if you count, depending on how you look at the wraps. Super, super easy. If you need more control, a lot of stuff you can now do with formatters now that we have the per-page insets.
We think web viewing apps or a lot of apps that are HTML-based will only need those 10 lines of code to print and print well. But if you do need the full power, full control of what you're doing, you can always use a renderer which can use any of the common 2D printing APIs or graphics APIs to do print. And then you can combine formatters with renderers to make it super easy. And then new in iOS 8, as we demonstrated, you can now separate the picking of the printer from the actual act of printing.
So more information, our technology evangelist is Paul Danbold. For those who don't know the name, Paul has been in printing for longer than I have, which makes it 23 years. And he is readily available and can answer many questions. We put up a new website this week, developer.apple.com/airprint, this is your source for all iOS printing-related stuff. There are a handful of sample apps there. All the documentation, all the reference document stuff that you're going to need.
There's also a link to the list of every AirPrint printer in the world, every model of AirPrint printer in the world, as well as information on licensing of the AirPrint technology. So developer.apple.com/airprint will get you everything. And then of course, if you've got some ongoing questions, you're always welcome to use Apple's Developer forums.
And then there's another plug for AirPrint Basics, which lists all the printers. I know you guys are all probably pretty experienced application writers already, but if you still got a few details, I do strongly encourage you to go back and watch the video for the "What's New in Cocoa Touch". So that's it. Thank you very much.
[ Applause ]