What's New in StoreKit

Session 303 WWDC 2017

Starting with an expert guide to implementing the In-App Purchase workflow, learn about Promoted In-App Purchases and how to use the new StoreKit APIs. Find out what's involved for your server and apps. And finally, get the details and guidance on asking for Ratings and Reviews, and responding to Reviews.

Good morning, everyone.

[ Applause ]

Welcome to What's New in StoreKit.

My name is Pete Hare, and I'm an engineer on the App Store Team here, at Apple.

In-app purchases represent a huge percentage of revenue, generated by apps on the App Store.

So, to be able to implement them and to sell content to your users.

And to provide a great experience throughout this process, is becoming increasingly important for you and your business.

Now, we're working on ways for you to do all of these things, even more effectively.

And we're here, today, to talk to you about some enhancements to the StoreKit framework.

StoreKit is the framework that powers in-app purchases, amongst some other store related abilities.

But we've got some new advancements in iOS 11.

Firstly, you're going to have the ability now, to promote your in-app purchases directly in the App Store app.

So, a user can buy an in-app purchase and complete that in your own application.

Secondly, we're introducing some enhancements to the subscription, auto-renewable subscription flows.

We've got new server to server subscription notifications.

This is really going to make your lives easier if you're dealing with auto-renewable subscriptions.


[ Applause ]

We've also got some new detailed subscription status information when you're dealing with service side management.

This is going to give you much greater insight into some of those business questions about individual users and their subscription states.

We also, introduced earlier this year, the ability for you to respond to user's reviews on the App Store.

And along with that, we have some new enhancements in the ways you can ask for ratings and reviews.

Now, before we go into some of these new features, I'd like to start with an overview of the in-app purchase process.

So, let's look at implementing in-app purchases in your application.

Now, in app purchases haven't really changed much.

They were introduced in iOS 3.

An in-app purchase is really the ability for you to sell digital content or a service inside your app.

So, when it comes to physical goods or services, it's not really appropriate for in-app purchases.

We provide things like Apple Pay, and you can implement your own payment systems to accomplish selling physical goods.

But when it comes to digital services, that's what in-app purchases are good for.

We have four different types of in-app purchases that you can use.

Firstly, we have consumable products.

Now, this type of in-app purchase is the kind of in-app purchase that can be consumed, as the name suggests, and used up by a user.

So, this might be gold coins in a game that a user buys and maybe spends.

And it doesn't persist around subsequent restores or new devices.

The second kind is a non-consumable product.

It's a little different than the consumable product in that it does persist.

So, this might be more appropriate for things like unlocking a pro feature in your application, or maybe, downloading a level pack for a game.

We also offer two different types of subscription products.

We have the nonrenewing subscriptions.

Now, as the name suggests, this is the type of subscription product that doesn't automatically charge the user at the end of the billing period.

You can kind of think of this one like a consumable product with an expiry date on it.

And of course, the last type is the auto-renewable subscriptions.

So, we open the categories of auto-renewable subscriptions to a much wider array of categories, last year.

And have seen some great uptake of that.

In this particular talk, we're just going to focus on these first two types, though.

Mostly, consumable and non-consumable.

We're going to be going into subscriptions in much greater detail, in the Advanced talk, this afternoon.

It's at 1:50 p.m. in the Grand Ballroom A.

So, if you're dealing with subscriptions in a particularly service side environment, I definitely encourage you to come along to that session.

We've got some great new enhancements, there.

So, let's look at how to implement in-app purchases in your application.

It starts with loading up your in-app identifiers in your application.

We're going to dive into each of these steps in a little more detail.

But I'll just give you an overview, now.

Using those in-app identifiers, you can fetch localized product information from the App Store.

And once you have that localized information for the products, you can display in-app UI to the user.

This gives the user an opportunity to tap that Buy button and agree to purchase it, at which point it's up to you to go ahead and request a payment.

The user then, elects to buy your in-app purchase and authenticate the payment.

And it's up to you, to then process the transaction that comes back from StoreKit.

Once the transaction's been processed, it's up to you to unlock the content.

Make that in-app purchase available to the user.

And finally, the last step is to finish the transaction.

So, let's dive into the first step, loading the in-app identifiers.

The in-app identifiers are really just kind of product skews that you set up in iTunes Connect.

Each product that you sell has its own identifier.

And when it comes to loading these in your applications, you can do it a couple of ways.

Firstly, you can just bake them directly into your application.

So, in this case, I've just got an array of strings.

Or the other way, of course, is to maybe fetch them from your own server.

Either one of these techniques will work, but the important thing is that you just have this set of strings, these in-app identifiers that you can use to go ahead and fetch product information for.

Which is the next step.

So, if you have these, it's just a simple step to go ahead and load up the product information.

Let's look at the code for it.

You take that set of identifiers and you pass it through to an SKProductsRequest initializer.

Set a delegate on that request.

And then, just kick it off using the start method.

Now, you've set a delegate method on this so you'll get a response in the didReceive response callback.

So, inside this callback you'll receive an array of products that match those in-app identifiers that you've sent up in the request.

Now, you can loop through these products.

And we'll just highlight some of the fields that are included on these product objects.

There's a localized title and a localized description for that product.

There's also localized price information about that product in the store that, that user's logged into.

And we also have the information here, about any downloadable content that might be associated with this product.

So, one more important point, here, just to highlight, is that you shouldn't cache the SKProduct that comes back in this point.

It's really important that you get up to date product information, by performing these requests regularly.

Because things like currency can fluctuate.

You know, a user might log out, log into a different store front.

So, the locale might change.

Make sure that as often as you need to, you're requesting new product information from the App Store, and not holding onto an instance of these SKProducts.

But now, you have your SKProduct object and you're ready to go ahead and show an actual in-app UI to the user.

So, when it comes to showing the UI, of course, this is really up to your application.

And every application's a little different in how you're going to present the products to the users.

It can have a large effect on sales.

So, I'd encourage you to really be careful about how you structure this UI.

And if you want to learn a bit more about that, we've got some information online on our developer website, here, to check out.

This has useful tips about how to format this particular page in a way that can, you know, improve your sales.

One tip, though, just on formatting the product price.

So, when it comes to the product price, this is the technique you can use to actually display that in your UI.

Create a number formatter object.

Set the number style to be the currency style.

And then, set the locale to be the product price locale.

Now, this is a really important step.

Because if you don't do this, it's going to default to the system device locale.

Which may not actually match the store that the user's logged into.

So, the user might be logged into say, the Chinese storefront, but have the device set to U.S. English.

That's important that all the pricing and currency stuff matches what they're seeing in the App Store.

So, make sure you set the product's price locale under the number formatting, here.

But once you've done that, you can just take a string from the number formatter, and you've got yourself a formatted string that you can display in your UI.

Another point, here, don't perform any currency conversion yourself.

There's no need to actually convert currency.

You can let StoreKit handle all this for you.

So, just take that number and price locale that you get and let the number formatter do the job for you.

The next step, though, once you've displayed your UI, is to request a payment.

So, at this point, hopefully the user's elected to buy your in-app purchase.

They've hit that Buy button.

So, at this point it's up to you to go ahead and request a payment of the user.

Again, this is a really simple step.

It's just a couple of lines.

You take that SKProduct that the user's agreed to buy, pass it into an SKPayment initializer to create a payment object.

Then, you add that payment to the SKPaymentQueue's default queue.

Now, as soon as you add the payment to the default queue, the user sees this great new looking in-app purchase payment sheet.

So, this is new in iOS 11.

[ Applause ]

And the user, of course, can just authenticate the purchase using Touch ID, and then, continue using your app.

So, we think this is a much improved design that's going to make that experience a lot nicer for users.

Now, at this point, I'll just take a quick sidestep to talk a bit about detecting irregular activity.

So, the ability to detect irregular activity gives us warning signs if potentially something fishy might be going on in this particular process.

Now, Apple has an advanced engine to detect and block irregular activity before it happens, in the best cases.

But there are some cases where this happens after a payment's gone through.

And it can only detect it after the fact.

Now, in those cases, we refund developers or users as appropriate, but that's not a great experience.

So, we try to ask for a little collaboration from you, at this point, to help us detect these things a little earlier.

Now, I'll just go through an illustration that'll probably demonstrate what I'm talking about a bit better.

Let's say I have three devices, here.

Three different users that are logged into different Apple IDs.

These three users are purchasing the same gold coin product from the App Store from your application.

Now, this is a really normal scenario.

This happens millions of times from millions of users around the world, every day.

But let's add in another piece of information to this puzzle that changes the picture, quite a lot.

Let's say that these three users buy gold coins in your application, but all these separate IDs are actually cashing these gold coins into the same game account on your server.

Suddenly, this picture looks highly suspicious.

So, how do we detect these sort of scenarios earlier on in the process?

We ask you to provide an account identifier with this payment step.

Now, this is really for applications that have their own account management.

So, if you've got, say, a server account and a user is logged in as a particular user.

And we ask for an opaque identifier at this step.

Now, what is an opaque identifier?

Well, we don't really want you to give us actual information about the user.

We already know the user's Apple ID, so don't give us that.

We don't want to know what the actual username is for the user or the password.

We don't want to know any of these details.

What we suggest here, is that you create a hash of the account name, or something like this, right.

This just gives us a unique identifier to be able to match these payments across different Apple IDs and associate them together.

It's a really simple step to be able to do this.

When you create the SKPayment that we just saw a moment ago, there's just an extra step you can do.

Which is to set the application username.

And here, you can just set that hash of the account name, and that'll just help us detect the irregular activity earlier on, in the process.

So, that's a really simple step you can do to make your payments a little more secure in your app.

Once the user's authenticated they payment, though, the credit card's charged.

And it's up to you to go ahead and process the transaction that comes down from StoreKit.

So, let's see what that looks like.

Right at the beginning of your application lifecycle.

And here, I'm doing it at the didFinishLaunchingWithOptions app delegate method.

It's important to set a transaction observer onto the SKPayment queue.

Now, here I'm adding the actual AppDelegate, itself, as my SKPayment transaction observer.

But you could use another object if you want to actually monitor these transactions.

The really important thing here, is that it's happening as early on in the application lifecycle, as possible.

See, transactions can come into this transaction observer any point during your application lifecycle.

So, make sure that you're registering it right at the start.

But once that's registered, you're ready to start receiving transactions in the callbacks.

There's this one callback updated transactions, which is kind of the center of where this all happens.

You receive an array of transactions that come in, and you can check the transaction state on each of these transactions.

And you'll look for a transaction in the purchased state.

This is a transaction that's StoreKit deems appropriate for you to go ahead and check for validity and unlock content for, accordingly.

There are some other states here, that we won't go into in this talk.

But one of the ones that I will call out, is the deferred state.

A transaction can come through in a deferred state if the user has asked to buy turned on.

So, a child might ask to buy an in-app purchase and a request goes to their parent for approval to actually approve the purchase.

And that could take anywhere between seconds, minutes, weeks, who knows how long.

So, it's important if something comes through in this deferred state, while they're waiting for an approval, that you allow access to the application.

Allow them to keep using your app, and don't let them get stuck on any kind of modal loading spinners or things like that.

The transaction will eventually come through as a purchased one, once it does get approved.

And you can just handle it like any purchase transaction.

In order to test out deferred transactions, we provide a way for you to do this.

You can create a mutable payment object.

And you can set the simulatesAskToBuy flag on this object.

Now, this is effective when you're using the Sandbox environment.

We're not going to go into the Sandbox as much, this talk.

But this is what it looks like, in code.

You just set that simulatesAskToBuyInSandbox flag to true.

And this just means that when you're testing out developing in-app purchases, this particular transaction's going to come through in the updated transactions call a deferred transaction.

So, you can just test out how you handle those particular cases.

When it comes to handling errors, couple of points to remember.

Now, not all errors that come through this process are equal.

And that means you really need to pay attention to the error code that comes through with a transaction.

So, maybe don't show an alert unless it's absolutely necessary to inform your user of a particular error.

You know, we see things like maybe a user cancels a payment, which has a specific error code.

And you don't need to show an alert that says user cancelled to the user.

You know, they hit the Cancel button, they know they cancelled.

You don't need to let them know, again.

It's also important to let StoreKit handle the transaction flow as much as possible.

And this means that you don't need to ask for confirmation for things like in-app purchases, once they elect to buy it.

We have that nice new payment sheet to do that for you.

And you can let StoreKit handle that.

Now, once a transaction comes through in the purchase state, I mentioned that it's important for you to verify that transaction.

How do we do that?

How are we sure that money has actually changed hands?

Well, we use the application receipt to do this.

This application receipt is really just like any receipt you get in the department store.

It's a proof of purchase that is evidence that the user has bought something they say they've bought.

So, in this particular case, it's a trusted record of the app and any in-app purchases that have occurred for a particular application.

Every app actually has an app receipt, because it includes information about initial app purchases and even information about the original free app downloads, as well.

This document's stored on the user's device, and it's issued and put there by the App Store.

And it's also a signed and verifiable document.

So, you can be sure that this is a document issued by Apple.

And you can use certificates to actually check that that's the case.

Finally, it's for your app, on that device only.

So, this receipt document can't be shared across devices.

And it can't be shared amongst applications on the same device.

Now, to be sure that the document that you're using to check these transactions is indeed a valid one, you do what we call receipt validation.

Receipt validation can be done a couple of ways.

You can do it directly on the user's device using on device validation.

And you can unlock features, accordingly.

Well, the other way is to use server to server validation.

So, you can take that encrypted receipt data, and you can send it up to your server.

And from there you can send it over to the App Store server, in order to perform some of those checks for you.

We're not going to go into the details about receipt validation.

And this talk that's going to be talked about, again, in the Advanced Session, this afternoon.

I'm going to talk about you know, how to read in this receipt data from the device.

And also, how to do the server to server exchanges for that, too.

But once you've confirmed that this receipt is an authentic document, you can go ahead and read in transactions and ensure that this transaction that's come through in this process is present in the receipt.

And that means that you've got a valid purchase ready to go ahead with for the next step.

Which is to unlock the content for your in-app purchase.

This is, obviously, a pretty important step.

To make the functionality that the user's bought, available to the user.

This is the step where you might download any additional content and make it available to the user.

If you are downloading content for in-app purchases, there's a couple of ways you can do this.

Apple actually offers two techniques for you to use, as well.

We have on-demand resources, which is an API that we introduced a couple of years, ago.

And we also have what I mentioned earlier.

The hosted in-app purchase downloadable content.

So, you can associate downloadable content through iTunes Connect that's accessed through the SKProduct object, directly.

Of course, the other way is just to host the content, yourself, on your own server.

Which is perfectly okay.

But if you do that, I just encourage you to remember to use the appropriate background downloading APIs.

Use NSURL session to make sure that these downloads aren't interrupted, you know, when a user exits your application.

Once you've unlocked your content, maybe you've made that pro version of your application available to the user.

You can go ahead and finish the transaction.

This is the last step in implementing in-app purchases.

So, it's important to finish all transactions that come through this process.

Even if they're in like an error state, you got to finish all transactions that come through in this flow.

And that includes when you're dealing with auto-renewable subscriptions.

Any renewal transactions that come in this flow, as well.

So, any of those, billing period renewals that come through, you have to make sure you take all of these through this process to finish them.

If you don't finish the transaction, they actually remain on the payment queue.

And they're going to keep on popping up in that updated transactions callback on every app launch.

So, make sure that you are finishing them properly and getting them out of that payment queue.

In fact, when it comes to auto-renewable subscriptions, we've got some details around billing retry that relies on up to date knowledge around the state of all these renewal transactions.

So, It's really important that you do keep these finished and up to date.

When it comes to finishing them, it's actually just one line of code.

So, there's no excuses.

You just pass the transaction through to the finished transaction callback.

This is a API on the SKPaymentQueue's default queue.

But once you do that, you've finished the transaction, that's the last step in actually implementing the in-app purchase flow on a device.

So, the user's now got access to that in-app purchase that they've paid for.

A couple of tips just while we're on the subject.

When you're in app review, you must have a Restore button if you've got non-consumable or auto-renewable subscription products in your application.

And this Restore button has to be a separate button from the actual purchase button.

So, it can be somewhere in your app, maybe buried in your settings, somewhere.

But it's just a tool to allow users to restore completed transactions.

And it's not just a backup tool.

You know. People use this all the time when they're dealing with maybe a new device.

If they go and buy a new iPad, and they want to unlock the content that they've paid for on their phone.

They use that Restore Transactions feature to be able to do that.

So, it's important you have a Restore Transactions button, somewhere in your application.

As I mentioned, though, it does only restore transactions for non-consumable and auto-renewable subscription products.

So, if you're selling consumable products or non-renewing subscriptions, you've got to persist the state of those things, yourself.

So, maybe you've got a game account, you might associate it with that account information somewhere on your own server.

In order to actually restore them, this is the API for it.

It's restoreCompletedTransactions as the method, and it's on the default payment queue.

If you call that, that's going to cause all the completed transactions in those categories to reappear on the updated transactions callback.

So, you can just do the same process that we just saw, check for them being in the purchase state, do receipt validation, unlock all the features accordingly.

There's a couple more APIs around the restoring completed transactions.

You can understand if it's finished or if there was an error with a particular process.

But the real thing to do, here, is just if you have a transaction observer registered early on in your application.

You can just handle all of these transactions as they come through that updated transactions callback.

So, just to summarize this process that we just talked about.

Always observe the payment queue and make sure you're doing it as early on in your application lifecycle, as possible.

Use an SKProducts request to request localized information about the products from the App Store.

And use that to display localized pricing information.

Use that technique we just saw with the number formatter, to make sure that your price is being displayed in the user's store locale.

Use the receipt to actually validate that the purchase has taken place.

This is an important security step and we'll talk a bit more about that, this afternoon.

You got to remember to make the content available to the user.

So, make sure they get what they've paid for.

And then, finish the transaction at the end of this process.

Make sure that you call finishTransaction and pass in that transaction object.

And then, somewhere in your app, have a Restore button to allow users to restore completed transactions onto that device.

So, that's a bit about implementing in-app purchases and that process.

Next, we're going to discuss the new ability to promote in-app purchases, directly in the App Store app.

And to talk a bit more about that, I'd like to invite Ross LeBeau up onto the stage.

[ Applause ]

Hi. I'm Ross.

I'm an engineer on the App Store team.

And today, I'm excited to tell you about our latest addition to the App Store.

It's called Promoting In-App Purchases.

And it's a great way to reach an even wider audience with everything your app has to offer.

So, before today, if a user wasn't actively using your app, your in-app purchases were pretty hard to find.

But starting in iOS 11, your in-app purchases will be discoverable, right in the App Store.

They'll be visible on your app page.

They'll be eligible for editorial feature.

And they can even show up in search results.

Not only that, but users will be able to begin a purchase right from the App Store itself.

We think this will be a huge improvement to how users view your in-app purchases.

So, how does it all work?

Well, promoting your in-app purchases is easy.

You'll need to do to things.

First, choose up to 20 in-app purchases to promote per app, and set them up in iTunes Connect with an accompanying image.

Then, implement a single delegate method in your app to handle the purchase info sent to you from the App Store.

In most cases, this implementation can be just a single line of code, and StoreKit will handle the rest of the transaction for you.

Also, if you want, you can override the order and visibility that they show up in, locally.

Now, this isn't required, but it can be useful in a variety of situations.

So, we've already gone into detail on how to do the iTunes Connect setup in the What's New in iTunes Connect session.

That was yesterday.

If you missed it, you can just catch it online.

But for now, let's dive in and take a look at handling your transaction info when it's sent to you from the App Store.

So, a user has clicked to purchase one of your in-app purchases in the App Store.

StoreKit will automatically open your app and send information about the transaction to you via a new delegate method on the SKPaymentTransaction observer protocol.

Now, you already have an object implementing this protocol, doing things like observing a transaction state, as Pete was talking about earlier.

So, you can put your new code for promoting in-app purchases right next to your already existing code.

It's good to know that if your app isn't already installed, the App Store will download or prompt the user to buy it.

In this case, it can't be opened automatically, so instead, the user will receive a notification.

And when they tap on that, then your app will open and be sent the transaction info.

So, what's the code look like?

Well, this is all the new code you need to get started promoting in-app purchases.

StoreKit will send you the SKPayment queue, the SKPayment, and the SKProduct.

Which is everything you need to handle the transaction.

And the SKPayment will already be set up with the SKProduct on it.

When you return true, the user will be shown that nice new in-app purchase payment sheet, so they can complete the transaction.

And that's it.

We're done.

Time to ship it.

Oh, all right.

Well, what if the user is in the middle of onboarding?

Or if they're creating an account?

Or if they've already unlocked the item they're trying to buy?

Well, in this case, you can hold onto the payment and return false.

Then, when the user is done onboarding or whatever they needed to do, simply add the payment to the payment queue as you would with a normal in-app purchase.

It's important that you add the SKPayment that was sent to you in this delegate method and not create a new one with the same product.

If for some reason you need to cancel the transaction entirely, just return false and no other action is required.

If you're going to cancel or defer a payment, you should definitely consider letting the user know, in some way.

What you don't want, is for the user to tap on the in-app purchase in the App Store, be brought to your app, and then, nothing happens.

They're going to think there's a bug, and that's not good.

Okay. So, now you've got this all set up.

You want to test it.

Right. Well, your in-app purchases won't actually show up in the App Store, until you've submitted a binary that has this delegate method.

So, we know you can handle the transactions.

So, instead, we've created a system URL for you to use.

This URL has the ITMS services protocol and three parameters.

The first parameter is action, and that's always purchase intent.

The next parameter is bundleID, which is of course, the bundle ID for your app.

And the last one is productIdentifier, which you fill in with the product identifier of the in-app purchase you want to test.

And once you've constructed this URL like so, you can simple send it to yourself in an iMessage or an email, and tap it on your device.

You'll now it's working, because your app will be opened automatically.

And you can test its behavior from there.

All right.

Now, we've gone over how to handle the payment info when it's sent to you from the App Store.

Let's take a look at the more advanced setup.

When you set up your promoted in-app purchases in iTunes Connect, you'll be able to choose a default order that they appear in on your app page.

You'll also be able to choose to set some to hidden, so that they don't appear, at all.

Then, when your app is running on the device, you can set overrides for these, locally, to change the order of visibility.

So, for example, if you're making a racing game you may want to hide in-app purchases for a car until the user has actually unlocked that car.

Then, when they do, you can move that in-app purchase to the top of the list and unhide it.

So, they've just unlocked the car, and now they'll see the most relevant in-app purchase right at the front of the list.

it's important to know that these are not synched across the bases.

They're stored locally on each device.

So, if you need to replicate the same behavior, you should make sure that your app locally can reproduce the results.

All right.

Let's take a look at some specific examples.

Here, we have an app called Forest Explorer.

This is an app we made up that helps people discover and travel to destinations.

This app doesn't exist in the App Store.

It's only this presentation.

So, here we're promoting three app purchases.

We have the Pro Subscription, which upgrades the level of detail the user sees and maps and directions.

We have the Fishing Hotspots and the Hidden Beaches packs.

Which simply unlock more destinations that follow those themes.

So, one thing you may want to do is, say a user has purchased the Pro Subscription in-app purchase, is hide this from your app page.

So, this is not something that StoreKit or the App Store does, automatically.

If they buy this and then, go to the App Store, they'll still see it there on your list.

Which might not make sense, because they can't buy it, again.

So, instead, what you can do is use the local visibility override to hide the app purchase.

And then, they'll only see items that are relevant to them on your app page.

So, what's the code look like for this?

Here it is.

First, you want to start by fetching the SKProduct so you have the most up to date information from the server.

Here, we'll fetch the info for the Pro Subscription in-app purchase.

Then, we have a new class for dealing with these local overrides called SKProductStorePromotion Controller.

You'll want to get the default controller.

And then, passing your SKProduct to the update StorePromotionVisibility forProduct method.

Along with the new visibility you want to set it to.

So, here we want to hide the Pro Subscription, since the user just purchased it.

That's all there is to it.

Pretty simple.

Now, if you want to check to see what overrides you've already set, start again by fetching the SKProduct.

Here, we'll look at the Hidden Beaches pack.

So, pass this into the fetch StorePromotionVisibilityFor Product method.

And what we can see here, is the visibility is done, default.

Now, this is because we haven't set any overrides, yet.

And it means that it will be hidden or shown based on what you've set as a default in iTunes Connect.

Okay. So, we've talked about overriding the visibility.

How about changing the order that your in-app purchases appear in on your app page?

Let's go back to Forest Explorer.

Now, maybe you've been looking at your metrics, and you notice that this user is going to a lot of beaches.

Could make sense to move the Hidden Beaches back to the front of the list so that they're more likely to see it.

And since it's something that's interesting to them, they might be more likely to buy it.

Now, the code for this looks very similar to updating visibility overrides.

You'll want to fetch the SKProducts for every in-app purchase you want to override the order of, so here we'll do all three.

We'll do the Pro Subscription, Fishing Hotspots, and the Hidden Beaches.

Then, create an array that has these in-app purchases in the order that you want to override them to be.

So, move the Hidden Beaches to the front.

Finally, pass this array into the updateStorePromotionOrder method.

And there you go.

It's been updated.

Now, if we want to view the overrides we may have set, already.

Once again, it's very similar.

Grab the default storePromotionController and simply use the fetchStorePromotionalOrder method.

Here, we can see that we get an array back and Hidden Beaches is in front, since we've just set that override.

Now, you don't need to use every in-app purchase in your array when you set the overrides.

You can actually use any subset of them that you want.

If you do, what'll happen is that subset will be shown at the front of the list in the order you've specified the override for.

The rest of your in-app purchases will be shown after those, in the same relative order as you've set in iTunes Connect.

Also, you can receive an empty array from this method.

This would mean that you haven't set any order overrides, at all.

And similarly, you could pass in an empty array to the update method.

And that would be the same as cancelling all the overrides.

You can think of this as using the empty set of overrides.

So, this is all the code there is for promoting in-app purchases.

The new delegate method and the test URL are available, right now, in the Seed we sent out, earlier this week.

And this order and visibility override will be available in a later Seed.

To recap on promoting in-app purchases, it's a great way to make them more discoverable, by promoting them in the App Store.

You'll choose up to 20 to promote per app and set them up in iTunes Connect.

Then, a user can tap in the App Store to begin the purchase.

The transaction info will be sent to your app as it's opened automatically via a new delegate method on the SKPayment transaction observer protocol.

Finally, if you want, you can override the order and visibility of they appear on your app page, locally at runtime.

Now, I'm really excited to see how you all will use promoting app purchases in your apps.

But for now, I hand the stage back over to Pete, so he can tell you what's new in working with customer reviews.

[ Applause ]

Thanks, Ross.

I can't wait to try out Forest Explorer.

Looks like a great app.

Well, now we've learned a bit about implementing in-app purchases and how to promote them in the App Store.

Let's look at some ways you can now interact with your customers.

So, in iOS 11 we've got this great new looking App Store design.

And this is a product page.

If you scroll down the product page, this is the new ratings and reviews section, with a new unified rating there.

And the user can just swipe through different reviews in order to read information about user's experience with your apps.

So, what's new in this regard?

Well, we've got a few new features, here.

The first one, you can now choose when you want your rating to reset.

When you release your application, you can decide if this is something you want to happen or not.

Previously, this would reset your rating every single time.

So, now it's kind of up to you.


[ Applause ]

We've also, recently added the ability for you to respond to reviews on the App Store.

So, you can have that dialog with consumers, now.

There's also some new ways for you to ask for ratings and reviews by the SKStoreReviewController.

And finally, we added a new deep link in iOS 10.3, that can link directly to be able to write a review in the App Store.

We also have added Helpfulness and Report a Concern to iOS.

So, what does that look like?

Well, a user can now 3D Touch on a review itself, and they get presented with this Helpful or Not Helpful menu.

They can mark them as helpful or not helpful.

They can even report a concern directly in the iOS app.

And when it comes to responding to reviews, we introduced this in iOS 10.3.

And the response has been really fantastic.

We think users have loved this feature and we've seen developers really utilizing this in a great way.

And when you respond to a user's review, the user gets a notification on their device, informing them of your response.

They also get an email, as well, detailing that response to their review.

Now, down at the bottom of this email, we actually have a link for them to be able to update their review.

So, we give them that opportunity to tap that link.

And they get a chance to actually edit their rating and perhaps change their review, as well.

And we've found that as users are doing this, when they're updating their reviews after receiving a response, across the board we've seen an average increase of 1.5 stars per review.

So, as you can see, it's a really great opportunity to see a better rating.

A better experience for the user, and also, a better rating for your app on the App Store, entirely.

So, for more information about this, we have a guide online about some techniques and the best ways to respond to reviews and to interact with your customers.

And we also chatted about this in the What's New in iTunes Connect session, yesterday.

So, if you weren't able to make that, I'd encourage you to check out the video for that, too.

When it comes to receiving reviews, there's a couple of ways you can do this, now.

You can prompt the user for reviews in the SKStoreReviewController class.

And we also provide this deep link to be able to write a review in the App Store, directly.

So first, let's look at the SKStoreReviewController.

This was a class that we introduced in iOS 10.3 And it provides a really nice clean interface for the user to be able to rate your application without leaving it.

So, they can now, just tap a star, hit submit, and rate your application in a really seamless experience.

They can ever write a review without leaving your application, now.

Now, if you're asking for reviews using another kind of alert or modal prompt, I just highly encourage you to start adopting this API, because at some point in the future, we are going to start requiring that any modal presentation, any modal prompts for reviews do use this API, instead.

And there are some restrictions in place for how this API can be used.

There's a limited number of requests per device.

So, we limit the amount of times a user gets bombarded with these alerts.

And the user can actually now, in iOS 11, switch it off in the Setting app.

So, they can go into the App Store Settings, hit a toggle to actually turn off these prompts for ratings.

So, we think this is going to be a better experience for users and for developers, alike.

A couple of tips for implementing this.

The SKStoreReviewController is a prompt, so it's kind of interruptive by nature.

So, think about doing this thing at the end of maybe, some kind of user interaction.

Maybe after a user has completed a task.

Maybe, then use that opportunity to ask them for a rating or review.

Don't interrupt them when they're in the middle of something.

It's also, not appropriate to use this API from a button.

Because you're not kind of guaranteed to have UI presented to the user, based on those restrictions we just saw.

So, it's not appropriate to use from some kind of embedded link in your application.

But when you do want to do it, this is what is looks like in code.

It's just one line of code.

But you can wrap it in your own business logic.

So, in this example here, we're checking to see if this particular user is the kind of user that we want to ask a review of.

And if we determine that they are, we can call the request review method on the SKStoreReviewController.

And that's the only thing you need to call.

And that'll present that rating prompt to a user while they're using your application.

The other way, of course, is this new deep link to write a review that I mentioned.

So, this was also actually introduced in iOS 10.3, but we're talking a bit about it, now.

This provides you a link to open your app page in the App Store.

But straightaway actually presents the write review sheet, or the edit review in the case of they've already written one.

And this is more appropriate for thing like user initiated actions.

So, in the case that maybe you do want a persistent link in your app, maybe a button in your Settings to write a review for your app in the App Store.

And it's a little different to the SKStoreReviewController, in that sense.

You can kind of think about it as being the opposite.

So, it's more appropriate from a button in your Settings, or some embedded content in your application.

Because it provides that consistent experience, a guaranteed action that's going to happen.

However, it's not appropriate to use from an alert.

I mentioned if you're going to use alerts to prompt users for reviews, make sure that you start to adopt SKStoreReviewController, instead.

This is how you actually form the deep link.

You take you app page URL, which you can get online from the Link Maker website, if you don't know what that is, already.

And you just append the query parameter action equals write review onto the end of it.

And that just means when the user arrives at your app page, they get presented with that Write Review sheet.

So, for more information about ratings and reviews and some of the changes we introduced earlier, this year, I'd encourage you to check out the developer website, here.

We've got some more information, there.

So, we've covered a few of the new features, today, for what's new in StoreKit.

Just to recap.

We talked about the way to implement in-app purchases in your application, that seven step flow for implementing in-app purchases.

Ross, got up here and discussed some of the newer ways that you can promote your in-app purchases, directly in the App Store.

So, you can now sell content to your users while they're browsing the App Store app.

We've got that new App Store design, featuring the new Ratings and Reviews section, including developer responses.

And we've seen that using developer responses, we've got some great new opportunities to actually see improvements in your ratings and reviews.

Better customer experiences, in that regard as well.

For more information about this session, we've got some links on the website, here.

And this is Session 303.

There's also, some related sessions, particularly this afternoon, with the Advanced StoreKit session.

And I can see you there, hopefully, if you come along.

We've got some more details about receipt validation.

We're going to go really in-depth into subscription management, persisting state across the server environment, and that kind of thing.

So, please come along and we've got some more content for you, there.

But that's it for today.

Thank you, for coming along this session.

And I hope you have a great lunch.

[ Applause ]

Apple, Inc. AAPL
1 Infinite Loop Cupertino CA 95014 US