What is StoreKit 2 and what are its new features?

Just like every year, Apple’s Worldwide Developers Conference took place yesterday. Without too much preamble, we are excited to share with you some key takeaways. 

In this piece, we’ll focus on StoreKit. As a quick refresher — StoreKit is a safe and easy way for users to complete in-app purchases across all Apple platforms. So, what’s new in StoreKit 2?

StoreKit 2: Key Points

Here are some of the main things about StoreKit 2 you should take away from the presentation: 

  • It’s designed with a Swift-first mindset. 
  • There are now new and enhanced APIs.
  • Transactions are becoming simplified and even more secure.
  • Customer support is enhanced as users manage their subscriptions from within your app.
  • Testing capabilities widen as you can test your apps in Xcode and the sandbox environment.

Now, let’s get a bit more specific.

The New APIs

The new StoreKit 2 APIs consist of five main areas:

  • Products
  • Purchases
  • Transaction information
  • Transaction history
  • Subscription status

Products and purchases are the building blocks of StoreKit. Hence, they are what we will cover first.

Products and Purchases

The StoreKit 2 product struct is a supercharged version of the StoreKit product object you’re used to. Additional data has been added to it. Specifically, Product types and Subscription info. Now, it’s easier to find out if the customer is eligible for an introductory offer.

Moreover, StoreKit 2 products are now forward-compatible with new features. Thanks to Apple adding a wrapping type called BackingValue, you can now retrieve data contained in the product by subscribing the products directly. 

What does this mean? If in the future, Apple adds data to products, you’ll always have the ability to access them in StoreKit 2. In simple words, you can now use the latest features to provide new functions to a larger portion of your customer base.

With StoreKit 2 you request products by calling a static function on the product type. This action requests product metadata from the App Store. However, due to the new Swift concurrency async/await pattern, the StoreKit 2 product request only needs one line of code. Likewise, purchasing a product is also a one-line task.

Purchase is now an instance method on the product type. This means that you can take the retrieved products and call purchase directly on them. In return, you get the result of your purchase inline in your code.

Of course, purchases aren’t all identical. So, if you want to modify purchase behavior beyond the default setting — you can, because StoreKit 2 has Purchase options.

A purchase option describes a single property of a purchase. Purchase options can be composed into a set and passed into the purchase method. StoreKit 2 includes purchase options for things like quantity, promotional offers, and an app account token. The latter provides you with a way to keep track of your app’s user accounts that began and completed a transaction.

The app account token is created by you and can be linked to accounts that your app owns. Overall, generating an App account token isn’t difficult. All it has to do is conform to the UUID format. 

Moreover, the token will be stored in the transaction info forever. Thus, if your app supports its account system, you can easily keep track of which purchases each in-app account has made. No matter which Apple ID or device was used for purchase.

Transaction Information

Having covered getting products from the App Store and initiating a purchase, let’s take a look at what happens when that purchase is complete. 

StoreKit is going to return a successful transaction to you with cryptographically signed information. There’s nothing new here. However, with StoreKit 2 there’s been an upgrade to in-app purchase transactions.

First, Apple’s StoreKit 2 will now provide an individually signed object for every transaction. Plus, from now on, in-app purchase transaction info will be provided in JSON format. Making it much more common and easier to work with.

Apple knows that secure cryptographic signing is an invaluable part of StoreKit purchases, so they’ll now be using a common standard across the web — JSON Web Signature. Additionally, all the information contained in the signed object will now be available through native StoreKit APIs. This makes everything a whole lot easier.

During the WWDC, Apple even showcased an example of how easy it is to set up and run products with StoreKit 2. In the tutorial, the engineer used StoreKit testing in Xcode. This lets you build and test your store before defining products in App Store Connect.

In order to add products to the sample online store, the following steps had to be taken:

  1. Make a product request using a set of the product identifiers that you want to display. With StoreKit 2, you can do this easily by calling a static method on the Product struct.
  1. After receiving the products from the App Store, you can separate them by type. This can be done seamlessly in StoreKit 2 since the Product type now provides a property for the type as it’s defined on the App Store server.
  1. In the example, the store owner sells three types of products — fuel, cars, and a navigation package. Fuel is a consumable product, hence all consumables go into the fuel array.
  1. Cars, on the other hand, are non-consumable. So, all the non-consumables go into the cars array.
  1. Finally, the navigation package is a subscription product with three service levels. So, all the auto-renewable subscriptions go into the subscriptions array.

Just like that, all the products are now displayed, solely with the help of one line of code.

Next, we need to get the “Buy” button to function. This is done by calling the purchase method on the product.

When a purchase completes, a PurchaseResult is returned. It lets the developer know whether the purchase was successful. To handle whatever it may be, the developer can just switch over them.

If the PurchaseResult shows “success”, you’ll also see a verification result which can be either one of the two:

  • Verified
  • Unverified

The great thing is — StoreKit 2 does the transaction verification for you. With your transaction verified, you can deliver the content to the user.

Once the user receives the content, you’ve got to make sure StoreKit finishes the transaction. Then, to get the UI updated, you have to return it.

In the showcased example, and likely in many of your apps, the app has an account database that the developer maintains. Hence, it’s natural to want to include the app’s currently logged-in user with the StoreKit purchase so that the information is always available to the App when it gets App Store’s signed transaction.

This can be done by creating an appAccountToken purchase option, using a tokenized version of the logged-in account, and passing that option to the purchase method.

Now, the purchase method implementation is all set.

Moving on, you’ve got to keep in mind that the transaction update listener needs to be started as soon as the app launches so that you don’t miss a single one. It’s best to do this as soon as your store is created.

Also, don’t forget to test the update listener by enabling the “Ask To Buy” in your Xcode test environment. It will then simulate a purchase response in a pending state.

You can do it by:

Selecting the StoreKit configuration file —> Enabling “Ask To Buy” in the Editor menu —> Running your app again

Hopefully, this summary helps you get a better grasp of how the new APIs work. To get the complete step-by-step visual, head over to Apple’s overview video. In the meantime, we will move on to the next section.

Transaction History

Apple is now providing a lot of new ways to work with transactions. A new set of APIs has been added for querying completed transactions in history. With a single API call, you can access all of the user’s past and latest transactions, as well as current entitlements.

Current entitlements contain two main elements — all the non-consumables in the user’s transaction history, and all the active subscription transactions. This provides you with everything you need to unlock all of the things the user has paid for in your app.

With StoreKit 2, all transactions are available immediately upon app download. Plus, they are automatically updated in real-time, on every device.

To summarize, this means that users won’t have to restore completed transactions when the app is reinstalled or downloaded to a new device. Can you already imagine how much less hassle there will be?

Subscription Status

Lastly, with StoreKit 2, there are several ways for you to get detailed information about a user’s subscription status. As you may know, there are three parts to the subscription status:

  • Latest transaction
  • Renewal state
  • Renewal info

Renewal info indicates the auto-renew status, auto-renew product ID, and the expiration reason. All signed using JWS! Plus, as you might suspect, StoreKit 2 can automatically validate the renewal info for you.

Subscription status APIs return an array of statuses. Primarily, because users can have multiple subscriptions to the same product. For instance, a user may have subscribed and then also received a subscription through Family Sharing. In this case, you should check the array to see what is the highest level of service they’re entitled to.

Now, let’s quickly cover what working with transaction history and subscription status APIs actually looks like.

Going back to the demo store, we can see that the shop doesn’t illustrate what the user has already purchased. This can be frustrating but is a problem that is solved with StoreKit 2.

With the new version, your app can query StoreKit for the products that have been purchased, thus keeping the UI up to date.

As you can see in the above screenshots, users can now view what products they have already purchased, as well as the statuses of their subscriptions.

We’ve covered the two ways that StoreKit 2 uses JWS to enhance security. Now, let’s dive into it a bit deeper and look at how you can do your validation.

JSON Web Signature

JSON Web Signature contains three parts:

  • Header
  • Payload
  • Signature

After validating the signature from the JWS data, there are only a few steps left to ensure the signed info is valid for your app and the current device.

  1. Make sure that the bundle ID in the signed info payload matches the bundle ID of your app.
  2. For added security, you can embed the app’s bundle ID in the app, rather than relying on an API call.
  3. Check that this value matches the payload.
  4. Perform a device validation check to ensure that the signed info was generated for the device it’s currently on. This is what it’ll look like:

Ready to Reap the Benefits of StoreKit 2?

Our Qonversion team is excited about StoreKit 2’s new powerful APIs for in-app purchases, JWS transaction information, and everything else we’ve covered above. After all, as the functionalities expand, so does the value we can offer to the end-users.

We are staying on top of all new developments and will certainly support StoreKit 2 in all of our products and services.

If you’re looking for a single place to manage subscribers and grant them access to premium content — look no further. Our Product Center provides full in-app purchases infrastructure so that there’s no need for you to build your servers for validating receipts.

Want to learn more? Don’t hesitate to reach out and stay tuned for new updates on our blog. We aren’t done covering the WWDC just yet.

More articles from WWDC 2021:

StoreKit 2 Capabilities Deep Dive

Apple’s 2021 updates to managing in-app purchases from the server

How can you provide better customer support and refund handling with Apple’s latest updates?