WWDC2013 Session 305

Transcript

X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
[ Silence ]
>> Good morning and
welcome to the session
about using StoreKit
for In-App purchases.
So ... [Applause] Thank you.
So why are we even
sitting here in this room?
Well, because more and
more apps are switching
to In-App purchases.
In fact, when I was
making the slides
on June 2nd, it was shocking.
This works?
An amazing 96 percent of the
top 25 top grossing iPhone apps
in the U.S. were using
In-App purchases.
Of course that number
has changed every day
and today it dropped
embarrassingly
to a miserable like 88 percent.
So apps are switching and we
want to better support them.
And we made a bunch of changes,
and we'd like to share
them with you today.
So first we'll talk about the
changes that we made to --
to StoreKit and then we'll
review the In-App purchase
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
process and highlight the
changes that you might want
to make, and also discuss a few
of the options and decisions,
and the APIs you might
want to use, as well.
Then we'll demystify
the test environment
because it's really
important to use it.
Then we'll have a
grab-bag of tips straight
from the app review team to make
sure you can pass the app review
with flying colors.
So first, what's
new in StoreKit?
So at the core, StoreKit
is a payment system.
It possesses transactions and
for every single transaction,
it hands the application
a receipt and the security
of the whole model
comes from the receipt.
And if there's only one thing
you remember from today,
is that the security
is in the receipt.
So you can decide
to make this as safe
as possible as you want to.
You can really choose
the safety level.
If your accountant warrants it,
you can do very, very secure
and you can do whatever what
with it, but in the end,
the security is in the receipt.
And it's not very
difficult to verify receipts,
but there's a bunch of
details you want to get right.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So we spun off a separate
session called, "Using Receipts
to Protect Your Digital
Sales," in Presidio
at 2:00 p.m. You'll learn all
the tools, the technique s,
the APIs to verify the receipt
and all the options you have.
So I very much recommend
that you attend that session.
Now, let's take a
step back and look
at the history of the receipt.
In 2009, IOS introduced
In-App purchases
and for every In-App purchase,
we give you a receipt and it was
up to the application to
store it and manage it.
And then in 2011, the OS X added
the Mac App Store and threw
in a new receipt
in this ecosystem.
It's the app purchase receipt.
It's a proof of purchase
for the application itself.
So when we added enough
purchases to the Mac App Store,
we decided to unite
all these receipts
into one big unified receipt.
And today, I'm very excited to
announce that iOS is switching
to the same unified receipt,
which proved to be
so successful.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
[applause] So, thank you.
I'm glad you appreciate that.
So, it's the same receipt
format for iOS 7 and OS X.
It is managed for
you by StoreKit,
which means we store it
in the [inaudible] system
and we give you an API to access
it anytime you want to check it.
And you can now validate
that receipt just like OS X
on the device, which means
you don't need your own
servers anymore.
[Applause and cheering] Some
people have implemented that,
I see.
And there's another bonus.
This receipt contains the orange
box, the app purchase receipt
and you can use this
for two things.
First, if you want this
extra level of security,
if you to make sure your
application has been really paid
for, then you can
check this receipt
and make sure has been
purchased on this device
and everything is legit.
But it also helps you if want
to transfer to the premium level
where the application is free
and you sell the content.
How's that possible?
So say your application
is stocked in the store
as a paid application and
at some point in time,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
you want to make this
application a free application.
The problem is that when the
user restores to a new device,
you have no idea when they
purchased the application.
So did they purchase the paid
version or the free version?
So you don't know what
content they're entitled to.
So, if you look into the
app purchase receipts,
you'll find a purchase date
and this will allow you to know
if your user is entitled
to content,
or if the user purchased
after you switched to premium.
Now of course, we are
talking about transition,
which means that we have the
old style receipts around
and to be very clear,
they are duplicated.
But fear not, your
existing apps will continue
to work, of course.
Even, in fact, if you take your
existing code and you rebuild it
against the iOS 7 SDK,
the application will
continue to work.
You'll still get your
receipts, but you'll get a bunch
of duplication warnings.
And I'm sure you got the --
you heard distinctive
slide about 93 percent
of the applications, of
the users having updated
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to the latest version
of the iOS.
That means people will
transition to iOS 7.
And that means it's high
time to transition --
it's time to start transitioning
to a new receipt style.
But in the meantime,
you probably want
to support both the old style
and new style of receipts
and the right way to do this is
not to check for the OS version,
it is to use weak linking so
you only keep the two good paths
around and you want to check
if your main bundle responds
to the selector for the new
API added to access a receipt.
Next is Volume Purchase Program.
We're adding a new
licensing model here.
If you opt into this
program then you are allowing
large-volume purchasers,
think large companies,
think universities,
think schools.
You're allowing them to buy your
application in bulk and then
for a school to assign
licenses to the students.
And when the school year ends,
the school can take the
licenses back from the students
and assign them to the
new batch of students.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So that really unlocks
the education market
and the large enterprise
market for applications.
Now if you look at it from
a device point of view,
when the school year ends
and the students walk away,
the school will revoke --
will revoke the licenses.
This will start a 30-day
grace period during
which the students can
still launch the application
and they can back
up their documents
and whatever they want.
They are warned about this.
But then when the 30-days --
the 30-day grace period expires,
the license becomes revoked.
And on iOS, when the
license is revoked,
iOS will prevent the
launch of the application.
And instead of launching,
it will display dialog
to explain the situation
and offer the students
to buy the application
to keep using it.
OS X has a different
security model.
On OS X your application
will have to launch,
discover it is expired, and
then exit with a special code
so that the finder can display
this dialog and offer people
to buy your applications.
But again, the security
is in the receipt.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So in both cases, it is the
application's responsibility
to check the receipt and enforce
and make sure the
application stops running
if the -- if it is expired.
And to do this, we added
new fields in receipts.
So we've just touched
the surface.
If you want to know more about
this volume purchasing program,
you can watch a video of the
session that happened yesterday
about extending your
applications
for enterprise and education.
And also you can attend the
session in Presidio at 2:00 p.m.
about validating the receipts,
which will tell you everything
about the new fields we
added to the receipts.
Next, hosted In-App
purchases can now be free.
And what that really means
is, you can use them for --
to distribute message content
that all the user's need.
So think like musical
instruments,
or you know musical samples
-- not navigation packages,
anything that's huge
and that you have
to distribute to the same users.
You can use host
in-app purchases.
You can upload this to the Apple
server and Apple will host this,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Apple will serve it, and
Apple will even download it
in the background
for re-application,
so it's very convenient.
In fact, many applications,
that's' the only
reason they had servers,
to back their applications.
If that's the case, you
don't need servers anymore,
so its way simpler.
But keep in mind that
they are In-App purchases
so they still -- you know, the
user still has to buy them,
although it's for
free, and authenticate.
And they still have to go
through the app review process,
but they're a very convenient
way to distribute some content.
Now, let's review the four types
of In-App purchases we have
in the Apple ecosystem.
On the one end of the spectrum,
we have consumable products.
It's for things like gold coins,
things you can buy
multiple times,
but every time StoreKit
hands it only once
through the application and
the application takes over
and manages the amount
of remaining gold coins
or whatever it is.
And because it's managed
by your application,
StoreKit does not
restore it to past devices
because you're managing it.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now on the other
end of the spectrum,
we have non-consumable
products and it's for things
like magazines, things
that when you buy them,
you own then forever.
And those are completely
managed through StoreKit
and StoreKit will -- will
restore them across devices
and manage them completely.
Now since we're talking about
magazines, if you are dealing
with periodicals
then you can use the
auto-renewable subscriptions.
And those -- what a user really
buys is a period of time.
The user buys a period of time,
a subscription period and when
that period finishes,
[inaudible] store will
automatically renew the
subscription period
and drop a transaction
into the device payment queue.
So it's, again, managed
by StoreKit.
And you also have the option
to provide a free subscription
period to the users in exchange
for them opting in to share in
their personal data with you.
And the data from the
field shows that a majority
of people actually
trust your applications
and trust your brands, so
they opt in to share the data.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now, for all the other types
of time-based In-App purchases,
you should use non-renewing
subscriptions.
You can view them
conceptually as consumables
because the user -- when the
user purchases them they're only
handed once to the application
and the application takes over
and manages the subscription
in whatever way
that makes sense
for the application.
So it is extremely flexible.
You can do any kind of
subscription model here.
But -- sorry -- in
fact, it is so flexible
that it has no duration
information inside the
purchase object.
It is really up to you to
implement it the way --
a way that's meaningful
to your application.
So that's typically used --
typically used for things
like access to fly charts --
the latest fly charts,
access to financial services,
all the professional apps.
Now if you summarize,
iOS supports all four
types of in-app purchases.
OS X supports only
consumables and non-consumables.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And as you've probably
guessed, today we're excited
to bring subscriptions
to OS X Mavericks.
So the first question we
expect is how can they make
that content available
on both platforms?
And the answer is you
can, but the product
and identifiers are
separate in OS X and iOS.
So you will have to use
your own account management,
track the subscription
on one platform,
and make the content available
on the other platform,
and that wraps the updates
for In-App purchases.
Now, let's go through the
In-App purchase process
and let's highlight the few
changes you'll have to make
to transition to new receipts.
And also on the way we'll
make a bunch of stops,
and we'll discuss all
the options you have,
all the APIs you can use
to deal with the content
and all the issues
connected to In-App purchases.
So I'm going to assume here
that you already know the basics
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of StoreKit and that you
probably have an application
to store and an iOS
application running.
Now if you don't, I will gladly
point you to the [inaudible]
on the website, and to the
introductory session we had last
year that you can watch a
video for on the website.
So what do we need to make
an In-App purchase process?
We need really three
large phases.
First you have to set up the
products in Action Connect
and if it's hosting In-App
purchases, if you have content,
you want to package your
content inside of Xcode.
Then the user can make the
purchase on the client --
the device or the Mac, and
when purchase happens you want
to verify receipts and
you can do this either
on the client or on the server.
So let's assume here
that you have set
up your [inaudible] already.
So when the user wants to --
sorry, the In-App purchase
process is this long process
of stages and the first thing
you want to do is figure
out what you want to sell.
And you really have
two major options here.
If you have In-App
purchases like game options,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
things just unlocking the game,
then you can just
bake the identifiers
into your application.
That's perfectly fine.
Now, if you have -- if you're
sending content like magazines
or comics, then you probably
want to fetch your identifier
from your server so that
it can be very dynamic.
So we know what we want to
sell now, but now we have
to fetch the information
about the product
to display to the user.
And to do this, you first want
to create a set of identifiers
and then with a set
of identifiers,
you can create a
StoreKit products request.
You want to add yourself
as delegate to request
and start the request.
And that's all there is to do
and the request will
be sent to the server.
And when it comes down from
the server with a response,
your delegate will
fire with either --
fire with error because
the device was --
may be offline, not very
interesting but you still have
to handle it or if you're
online -- that's a good case,
you will get, "Did
receive response."
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And the response will
contain two things.
The first thing is invalid
product identifiers.
It's the unlucky case where
you ask for information
of the product that is
not in the store anymore
and that could be
because maybe you removed
from the store Action Connect,
or maybe you just
didn't make it available
in this specific country
for any kind of reason.
So, it's a case to keep in
mind, but in most of the cases,
the product is valid and
you will get a product
rating response.
So, that production rating
contains StoreKit products.
And each of those has all the
attributes you want to use
to display the -- to
display the contents.
So, you'll find a title
localized in the country
of the store accounts.
You'll find the description
localized for the same country.
You'll find a price in the
currency of the store accounts
and you'll find the locale,
which contains the currency.
And if it's a hosted
In-App purchase,
well you'll also get the content
size and the content version.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And you can use this
information for things
like offering the user to
upgrade to a new version
or just telling then
they're up to date.
So there's one question
we get very often.
How do you display
the product price?
And it's difficult,
dollar goes in to franc,
Euros goes in the back,
where does the Yen go,
and then you have
decimal separators.
So the best way to deal with
this is to be super lazy.
And we have this class
in the system called
NSNumberFormatter.
And if you create one of
those and you said it's style
to be a currency style,
and you set it's locale
to be the locale you got
from the product response,
then all you have to do
is go string from number
with the price you
got from the store
and this gives you a string that
you can display to the user.
So it's pretty simple.
What you should really not
do is try to do any kind
of currency conversion because
the price the store gives you
and the price currency that the
store gives you is what we will
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
charge to the user.
So it is the price that should
be displayed to the user.
So that's the best way to do
it, just display the price as is
and get help for formatting
the price with the unit
and all these kinds of things.
Now we have information
and now it's time to kind
of expose the user to the goods.
You want to show the in-app
purchase you are to the user.
And this is completely
up to the application.
Why? Well, because only
you know your application.
Only you know your content.
Only you can actually present it
in a way that does it justice,
in a way that's attractive,
that fits the game play,
or the application style.
So it's something that's worth
investing some time and effort
in to get it right because
when you get it right,
it has a huge impact.
It shows dramatically
on the sales numbers.
So for example, if you're
selling comics then you want
to build a comic store,
a gorgeous comic store.
This is comiXsology.
Look at that, it has
a 99 cent specials.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
It has [inaudible] Sprint.
It is attractive.
You can browse.
You can discover.
It has all the features you want
to have in a real comic store.
Now if you're a game and your
currency is like, you know,
gold coins, then again you want
to display these gold coins
in a way that fits
your application,
in a way that fits the game
play, so at the right moment
in the game so that people
are in the right mood
and they don't feel like
they're pressured to buy.
This is Heyday.
It's a free application
yet its number three --
it's the third top
grossing application today.
So that really shows that when
you do it right, it works.
So let's assume here
that you do it right,
because why else would you
do it, and make the purchase.
So the user has clicked
this bag of coins
and you want to make
the purchase.
So to do this you want to
create a StoreKit payment object
with the product you get
from the product response,
and then you add this
payment to the payment queue,
and that's all you have to do.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
StoreKit will take over.
StoreKit will start the dialog
to ask the user to authenticate,
and then StoreKit
will also ask the user
to make sure they really want
to buy this bag of coins.
And if the user says buy,
StoreKit will send the payment
request up to the server.
So I'm going to interrupt
the smooth flow here
and open a parenthesis
about irregular activity.
So Apple has an advanced engine
to discover irregular activity
and block it before
it even happens
and that's the best case.
But there's cases where we can't
detect it before it happens
so we can't block it.
So the purchases go through
and then we have to --
we will eventually detect
it anyway so we'll have
to refund the customer.
We'll have to pull back
the function developers
and that tarnishes everybody's
reputation; tarnishes ours
and your application's
name might be associated
to the scheme.
So it is in our -- our
interests are aligned.
It is in our interest
to block the activity
as much as possible.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So here's one case where
we're going to be asking
for your collaboration.
Imagine three devices are
making In-App purchases
with three different --
three different Apple IDs.
There's really nothing
suspicious here.
There could be three,
could be dozens.
That's what the story's about.
Its millions of devices
making millions of purchases
with millions of Apple
IDs, so it's really hard
to block this kind of
activity when it's fraudulous.
But now if I tell you, "Oh,
all these devices
are buying gold coins
and all these devices are
crediting those gold coins
to the same game
account," then suddenly
that picture becomes
highly suspicious.
And it's something
that, if you help us,
we can detect and block.
And to do this, we've added
API in StoreKits for you
to provide us with an
opaque account identifier.
So let's be very clear.
It has to be an opaque
identifier.
That means we don't want to know
your account names or users.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We really don't want
to know about this.
The only thing we want to
be able to do is in fact
if multiple devices
are making purchases
for the same game accounts,
so it has to be opaque.
It has to be your user account.
So don't give us the Apple
ID, we know this already.
Don't give us your
account's name; we don't want
to know the account's name.
That's really your
business, not ours.
Don't give us the
password, obviously.
What we suggest you do
is hash the account name
so that gives you -- that gives
us an opaque identifier that's
going to be the same across
devices yet will not allow us
to identify your accounts.
And to do this, when you
create your payment object,
you only have to set the
application username property
to be that hash of
user accounts.
So let's close this in
unpleasant parenthesis
and go back to the
In-App purchase process.
So you have issued the purchase
and the store will be processing
it, and it will come back
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to the device as a transaction.
So you will be informed, because
your payment queue server will
be invoked with data
transactions
and you'll receive no change
all in array of transactions.
The first thing it will
do usually is eat right
through those.
For each transaction
you want to check
and examine the transaction
state.
If the state is purchased it
means the transaction succeeded.
So, so far, you are accessing
the old style receipt
by calling the receipt property
of the transaction
and this is changing.
Now, the new way to
access the receipt is
to call app store receipt
URL on your main bundle,
and this gives you
a URL to the receipt
in the [inaudible] system
and then you can load it
with your favorite
NSData methods.
So that's the only
change you have to do
to get to new receipts.
And once you have the
receipts, you want to verify it.
And again, you choose the level
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of security you want
to implement.
You can do it as simple as you
want or as strong as you want.
You can verify on the device,
-- that's the Mac or the phone,
or you can verify
on your server.
And if you're the kind of
extremely cautious person,
you can check on both, as well.
So, first option evaluating
the receipt on the clients.
It is the preferred method.
It is the exact same validation
as you have been doing iOS X.
It is exactly as secure.
And because in-app purchases
have receipts all the time,
you can access the receipt
any time, even outside
of the purchase process.
So if you have a comics
application and user navigates
to a comic to read it, that
might be the right moment
to go check the receipt
for the comic to make sure
that the user actually
purchased the comic.
So you can do this any time
and because it's local,
of course it works offline.
Now the other solution is
to evaluate the receipt
on your own servers.
In that solution you want to
first open a secure connection
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to your server and send a
receipt up to your server,
and then your server can turn
around and forward the receipts
to the Apple validation servers.
And what the evaluation servers
do is they crack open the
receipts and they return a
pay load, adjacent pay load,
easy two parts, that contains
all the fields of the receipts
and results go to tell you
oh that receipt is valid.
So then your server
can process that.
In addition, if you are dealing
with auto-renewable
subscriptions,
your server can send
a shared secret
to the Apple validation servers
and that will tell the Apple
validation servers that "oh,
if the transaction
auto-renewed --
I'm sorry if the subscription
was renewed then the Apple
validation server will
return the renewed receipt
to the server."
And that's very important
because that means the server
can manage the subscription
complete server side without the
device being involved anymore.
And if you are a newsstand
application it means the server
can determine which
issues to push to devices
so it's very convenient.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So again, you want to validate
the receipt of your server
and you own the secure connect.
You only keep it
secured as needed
so of course we recommend
you use SSL,
extended verification
certificates,
certificate pinning,
whatever you want to do
to ensure you're talking
to your own server
and the content hasn't
been tampered with.
As we saw it's great for
auto renewable subscriptions
because you can move all the
subscription logic server side.
But the downside is because
you're talking to a server,
you have to be online so the
application has to be aware
that if it's offline it will
have to deal with the case.
Now, what you should absolutely
never do is check the receipt
from your application directly
against the Apple
validation servers.
Why is that?
Well, you don't own both
ends of the transaction --
of the connection so you can't
make that connection secure,
that means you can't trust it.
And if you're dealing with
subscriptions then you will have
to embed your shared secret
into your application,
which is kind of fragile.
And you want to send
it across a connection
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that you really know
you can trust.
So that's two, actually
three reasons not to do this.
And again, validating receipt
is not very hard, but you have
to get it right and
there's a bunch of APIs
and tools you can use
to help you with this.
So again, I'm going to refer
you to the session in Presidio
at 2:00 PM to learn all
the, you know, ins and outs
of receipt validation.
All right, so we have determined
that the receipt is valid
and now it's time
to deliver the goods
because the user paid for them.
So there's five choices here.
If you just have to unlock
something in your application
like a weapon, then just
unlock it, that's very easy.
Now, if you want to download
digital content then you have
four APIs you can use.
You can use host In-App
purchases as we saw earlier.
We can use newsstand
kit for periodicals.
In iOS 7 we're adding a new
API to download contents
in the background and you
can also use the legacy
classic downloads.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So first, host In-App purchases.
They are just regular
In-App purchases
with content associated.
So it comes from
the Apple servers.
That's great because if the
application becomes an overnight
hit, which I honestly wish it
would happens, you won't have
to scramble to buy servers and
bandwidth overnight and try
to kind of, you know, face
all the server downtime
and these issues because
Apple will serve these In-App
purchases, these
host In-App purchases
and we'll scale them
necessarily.
And also because they're
downloaded through StoreKit
and StoreKit's a background API,
they will continue downloading
in the background, as well.
And they are in-app purchases
so they go through review.
And there's one limit to those.
It's that you can only have --
I mean each In-App
purchase can only be
up to two gigabytes in size.
You can have as many products as
you want, but each of them has
to be -- is limited
to two gigabytes.
So quick overview how the API
works so you can know what
to look for in the
future, when you get --
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
when you're payment of
server fires with updates
to transactions, if a
transaction is associated
with a host In-App purchase,
the transaction will have
an array of downloads.
And to start them you can
just tell the payment cues
to start the downloads
with this array,
and then the downloads
will start,
and as they progress your
payment queue server will fire
with update downloads.
And each of these
download objects
in the array you
will find a progress,
you'll find the time
remaining, you'll find the state
and if things go wrong,
you'll find the error.
When the state reaches download
state finished then you can
access another property called
content URL that tells you
where the file landed
in the file system
so you can access it.
Now, if you're dealing
with periodicals you
have another option.
You can use Newsstand
Kit downloads.
Newsstand Kits downloads
from your own server
to your application
in the background
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and gives you a fine-grain
control
of the credentials
and authentication.
And the bonus that
Newsstand Kit offers is
that when the download finishes,
the application gets woken
up so it has a chance to look
at the file and updates its icon
in the Newsstand folder
to be the latest cover.
So again, high level
overview of the API.
It all starts with a
Newsstand Kit library.
And when you want to
download something,
you want to first add a
Newsstand Kit issue with a name
and a date that you can get
from the direct response.
Then you want to
wrap the download URL
into an [inaudible]
recall subject.
And with this subject, you
can create Newsstand Kit asset
download object.
So if you followed the
library contains the issues
and the issues contain
Asset downloads.
So when you're ready to
download, you can just scroll
down to the delegates on the
download, and this will begin
to download and this make
your object the delegate,
so it will get informed
whenever that makes progress
or finishes downloading.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So we mentioned that
Newsstand Kits was downloading
in the background.
So potentially the
application could exit
and then launch again.
So the question is how does
the application reconnect
to downloads that have been
progressing in the background.
Well, the Newsstand Kit library,
again, is the starting point.
It keeps -- it maintains
for you,
a list of the downloading assets
so you can access this list
when you launch your application
and for each of those,
we call the same method,
download with delegates.
This will reconnect
you to download,
make your object the delegate,
and all the delegate
methods will fire exactly
as the application and never
go into the background.
So it's very simple, but
it's only for periodicals.
Now, in iOS 7 we've
added a new API
to download in the background.
So it's only iOS, it lets you
download from your own servers.
It lets you download
in foreground
and in the background, and you
can control the authentication
pretty precisely.
And an added benefit
is its power efficient.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So as long as the application
is in the foreground,
then the content is urgent,
we'll get it as fast
as possible.
But if the user backgrounds
the application,
then maybe that content
isn't that urgent anymore,
so iOS will use its
best judgment
to find the appropriate
moments to download this
without draining the battery.
So again, a high level
overview of the API.
To initiate the download,
you first want
to create an NSURL session
configuration object
and we have a factory method for
this that creates one for you
that is pre-configured to
continue in the background.
And all you give it is an
identifier that's going
to be very useful
for reconnecting
when the application
launches again.
And then the real
object you want
to create is an NSURL session
and you can create this
with a configuration object.
You give it your
object as a delegate
and you can give
it the delegate cue
so that you know what cue the
delegate methods will fire on,
very convenient for
multithreading.
So again, you want to wrap your
URL into a URL request object
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and you want to create an
NSURL session download task.
That's an object that as
soon as you create it,
will start downloading into
temporary file location.
And because you are
the delegates,
your delegate methods will fire
every time there's progress
so didWriteData is the right
place to compute the progress
and display to the user.
When the download finishes
you'll get didFinishDownloading
to your URL and this
will give you the URL
of the place the
download [inaudible] in.
Usually the first thing you want
to do there is access the file
and copy to a safe place.
And again, this application
downloads in the background
so you have to be able to
reconnect to the downloads,
and it's very easy
with this application.
It happens at the UI
application delegate level.
So the UIApplication
protocol go to new method
and your application delegates.
When the application
launches, we'll get called
with handle events with
background URL session.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
This will give you the
identifier for the session
that just -- that you
have to reconnect to
and a completion handler.
So you want to use the same
code to recreate the session
and this will reconnect
you to the session.
And because you passed
your objects
as delegates your delegate
methods will start firing again
exactly as if the
application had never been put
in the background -- so very
convenient, very simple.
Once all the delegate
methods are finished firing
and you finish processing and
updating the UI and do all
that you have to do, you only
call the completion handler.
So for now the best thing you
can do is store it somewhere
so you can use it later.
So we just scratched
the surface of the API
and it has many more
bounties to offer.
So if you want to know more
of this API download new
background then you're welcome
to watch a session about the
Foundation Networking session --
the video from the session
that happened yesterday.
And finally, you can keep
using the legacy download APIs,
but it's not a good idea,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
actually because when the
application gets backgrounded,
the download stops so
that means you know this.
Your user is stuck
looking at a progress bar
and user is afraid
to exit the app.
User's afraid to do anything
because it will stop
the download.
So it's not the best experience.
Now of course some applications
use begin background task
and they use it to get
some background time
to finish downloading,
but it was never meant
for doing downloads.
In fact, in iOS 7,
begin background tasks
has changed semantics.
It no longer prevents
the device from sleeping.
So you will get your 10 minutes,
but maybe not right now.
Maybe you'll get them when the
iPod touch has left the home
and has no Wi-Fi
connection anymore.
So for downloads, not
a very good experience.
So we recommend that you
use the other options now
that we have really
good options.
And finally you have
the [inaudible] assets
and the final step is to
finish this transaction.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Again, not change here.
You have to finish
the transaction
by calling finish transaction.
And it's the right thing to
do, but if you don't do it,
it's actually terrible.
If you don't do it, the end
finish transactions will stack
up and you have all this backlog
and every time you launch your
application StoreKit will notify
your payment queue server
every single application launch
of every single unfinished
transaction,
and this slows down your app.
So, for the user's -- user's
stuck waiting, it's not great,
but also StoreKit will
have to talk to the server
to confirm the transactions.
So if user is on cellular
you will incur some cellular
data consumption.
So there's no point
in doing this.
So it's very simple to just
finish the transactions.
And that concludes the in-app
purchase process overview.
So there's one best
practice I'd like to mention.
To get your delegate
method's goal you have
to install the payment
cube server.
And you guys are already
doing this, but don't wait
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to make a purchase
to install it.
You have to do it right when
the application launches
because as soon as the
application launches,
it may receive transaction
any time.
Classic example,
you try to make a --
you try to make a transaction
and you lost the connection.
So transaction will
have completed
when the application
was not running anymore.
So the next time you launch it,
you will find the transaction.
You should process
it; otherwise,
the user has lost some content.
The user might have received
a gift code and redeemed
that gift code inside
the app store.
And when the user
launches the application,
they expect that gift to be
there so you have to process it
as soon as the application
launches.
And if you do periodicals then
when you launch the application,
the subscription might
have renewed and you want
to take this into account.
So as soon as you
get app, you know,
as soon as you get app
did finish launching,
it's the right moment to
install the payment cube server.
And finally, for real,
restoring in-app purchases --
nothing changes except
the API you call
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to get the receipt
so no change here.
And that wraps our kind
of quick over flight
of the in-app purchase process.
Now I'd like to discuss and
demystify the test environment
because it's something
that's a very powerful tool.
It's something you
should really use
to make sure your in-app
purchases behave correctly.
So today I'm going to call
it SendBox, but it's not
to be confused with
the other SendBox,
the one that limits access to
your application resources.
So SendBox today means the test
environment of the app store.
So the app store has a
production environment
and its evil twin, the SendBox.
So when the application
is talking
to the store they can be
talking to either the SendBox
or the production store.
How do you determine
which one is very simple?
It's based on the
certificate that was used
for signing your application.
So when you develop your
application it is signed
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with the development
certificate.
So the OS would point
your application
to the production store
-- sorry, to the SendBox.
Development hit SendBox.
Now, if your application
is signed
with app store certificates
and the only way
this could happen is
if the user downloads the
application from the app store,
then the OS will point it
to the production store.
And if you're ever unsure
because you've messed
up some accounts or something,
just make internet purchase
because you'll hear this dialog
and if you see this line,
it means you're hitting
the SendBox.
So what's the main difference?
First of all, the SendBox does
not charge you, which is great
because you want to test
as much as possible.
And -- yeah, you can laugh.
And if you get a SendBox
receipt is it not backed
by a financial transaction,
therefore, it will not validate
against the production
store validation servers.
So you can feel free
to use the SendBox.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
These receipts will not
validate against production.
And if you want to implement
the Volume Purchase Program,
then we mentioned that the
receipt will contain new fields.
And we have API in the SendBox
to request a receipt that's
either expired or revoke
so that the application
can test how it behaves
when licenses are
expired or revoked.
And of course, if you get a
revoked receipt from SendBox,
iOS will not prevent your
application from launching.
Otherwise, you could
never test your code.
And the final thing to
know about SendBox is
that it makes time
fly faster, for real.
This is great if you
do subscriptions.
The rule of thumb is that
one year becomes one hour,
so a yearly subscription
renews every hour
and it will renew six
times, and stop renewing
so you can test your code
for renewing subscriptions
and you can test your code when
a subscription stops renewing.
So in practice, that means
you have to first log
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
into Access Connect,
create a test user,
test users are not valid
in the production store,
there are two different sets,
it's a source of confusion.
Its two different sets of users.
Then you want to
create a product.
You want to build your app
and you want to sign it.
And on the Mac there's
one extra step.
On the Mac you have to
launch the application once
from the finder, and when the
application detects there's no
receipt and exits
with the magic code,
the finder will intercept this
magic code and fetch a receipt
for the application
and relaunch it.
That is how you get a receipt
on the Mac the first time.
If you launch the
application from Xcode
and the application
exists with a magic code,
the Xcode will just like
intercept this and submit,
and nothing will happen.
So launch the first
time in the finder.
That's a very frequent,
you know,
kind of head-scratching case.
And that's all you have to do.
Next thing is just buy
products, as much as you can.
So, to summarize, when you're
developing the application is
signed by your development
certificate.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So the OS will point
it to the SendBox
and you can get a SendBox
receipt and forward it
to your own test server.
And your test server
will let you get
that receipt against
the SendBox.
So, things just work.
Once the application is live
in the store, it is signed
by the store so if the
production application,
you will hit the
production store.
You will get production
receipts,
you will form those production
servers and you'll validate
against the production
store, everything works.
Now there's one case you
really have to be aware
of because it affects
app review.
During app review,
your application
comes from the store.
So it is production signed.
But the reviewers don't want
to charge anyone for reviewing.
So they will point the
application to SendBox.
So your production application
might get a SendBox receipt
and forward it to your
own production servers.
And if the server
tries to validate
that against the Apple
production validation servers,
it will fail, and you
don't want this to fail
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
because this will
fail at review.
So, what we recommend to do, is
to have your service first try
to validate the receipts in
the production environments
and if it fails with
the area code 21007,
pretty easy to remember,
then you want to turn back,
and fall back, and hit the
SendBox validation servers.
And if you do this, you'll
pass the review easily.
So, talking about the app
review, I'd like to finish
with some feedback from the app
review team but make no mistake,
we want your application
to pass that review.
We want them to be in the store.
We want them to have a great
user experience and we want them
to have a consistent user
experience especially
when transactions are involved.
You want that to be
super clear to the user
so they all have
to be hit the same.
If they don't be hit the
same, then the use --
the user's going to be confused.
They'll be confused,
they'll like hesitate,
they'll be fearful and
that's something we'd
like to leave the
to competition.
So the first thing you have to
do is have a restore button.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
If you have non-consumables, you
want to have a restore button.
If you don't and the user
restores the application
to new device, they have no way
of restoring the
content they paid for.
So they have lost content.
It's a terrible user experience.
So if you don't have
a restore button,
the application will
get rejected.
And another misconception,
restoring purchases
is a free process.
You get a new device, you
install the application,
restore the purchases.
It's free; it's to
get your content back.
The purchase process is to get
new content and pay for it.
It's really different processes.
And you want this to be
very clear for the user
and so they have to
be separate buttons.
No need to merge them.
If you are a news stand
application, as we mentioned,
you can give an incentive
for people
to share their personal data.
So you will receive
personal data,
so to make sure you
treat this properly,
you have to have a
privacy policy and you have
to feel your [inaudible]
connects.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Otherwise, this is an
automatic rejection.
Also you want to
make it very clear
to the user what
they subscribe to,
even before they
purchase the app,
so you want to put the
subscription information
directly into the
marketing text.
We have a schedule in the
application store guidelines
that you can use for this.
And free subscriptions
-- it's okay to use them.
In fact, we love them but
they are for free stuff.
They should not be used as a
way to get people to subscribe
to a temporary promotion and
then you raise the price.
In fact, if you try to
do this, it will fail
because the moment
you raise the price,
the store will stop renewing
because the users haven't
agreed to the new price.
So, free subscriptions
are for free publications.
And even though they're free,
that doesn't mean you
can auto enroll the user
or subscribe the user because
the user still should be
in control of the content
that goes into the devices.
So even a free subscription,
they should have a
subscribe button.
And in Newsstand, it is
totally okay, in fact it's great
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
if you offer the
users the option
to purchase individual
issues of the magazines.
But you also have to have
the option to subscribe
to the magazine because that's
what Newsstand is all about.
It's having content magically
delivered to your device
when you -- and it's
there when you wake up.
So if you are not
a Newsstand app,
but you do auto renewal
subscriptions,
it's almost the same case.
You might be exposed to
personal data so you have
to have your privacy policy.
You have to give
the users an idea
of what they're going
to be subscribing to.
So you have to put the
subscription information inside
the marketing text.
And you have to think
about what happens
to the user if they subscribe.
So when the user subscribes,
you know, they pay some money.
They should get something.
The latest issue
should become downloaded
or even downloaded
automatically.
But what you shouldn't do
is have the user subscribe
and then nothing happens.
They should get some content.
Again, paid subscriptions,
they're totally fine
but they're offered
paid contents.
You can't ask the user to pay
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
for things he could
get for free otherwise.
And apps that do
services, professional apps,
they usually -- they
should use their flexibility
of non-renewing subscriptions.
And talking about the
non-renewing subscriptions,
it is okay to ask
user to register
but it should be optional.
That is, users can use
your app and if you want
to track them, offer
to register.
They can register if they
want to, that's great.
Don't make it compulsory unless
your application has features
that users can only
get through accounts --
you know, through
their accounts.
And the final word
is about purchases.
They just must work because
the app review team will make
purchases and if the
purchases don't work,
they can't approve
the application.
So purchases have to work
and that's why we have
this test environment.
That's why we ask that
you test your purchases
as much as possible.
And the best way to pass app
review easily is also the best
way to get good user feedback
and read reviews and loyalty.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And it's also the best
way to get great sales is
to have a clean, easy
to understand, simple,
entertaining, pleasant,
and above all,
rock solid user experience.
And that's all I
have for you today.
So if you have any
questions, feel free to talk
to our evangelist Paul Marcos.
We have updated the
Commentator Developer websites
and the Apple Developer Forum
are a good place to ask --
look around and ask
a bunch of questions.
That's it.
Thanks for using StoreKits.
[ Applause ]
[ Silence ]