Transcript
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
>> 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,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
for the shared UI
printInteractionController.
You'll implement
printInteractionController
ParentViewController.
So you'll tell the
printInteractionController
which view should be a parent.
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
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 ]