Streaming is available in most browsers,
and in the WWDC app.
-
Introducing StoreKit Testing in Xcode
Discover StoreKit Testing in Xcode — a local environment for testing your in-app purchases without needing to connect to App Store servers. We'll show you how to set up a test environment, create a StoreKit configuration file, and prepare to validate receipts locally. We'll also explain how to test a variety of in-app purchase scenarios and automate those tests with the StoreKitTest framework, and cover the latest improvements to testing in the sandbox environment.
Resources
- Have a question? Ask with tag wwdc20-10659
- Search the forums for tag wwdc20-10659
- Setting Up StoreKit Testing in Xcode
- StoreKit Test
- Testing at All Stages of Development with Xcode and Sandbox
- Testing In-App Purchases in Xcode
- Testing In-App Purchases with Sandbox
Related Videos
WWDC 2020
WWDC 2018
WWDC 2017
-
Download
♪ Hello, and welcome to WWDC. Dana DuBois: Hello, and welcome to Introducing StoreKit Testing in Xcode. My name is Dana, and I'm really excited to show you all the great new features we're introducing this year that'll make building and testing in-app purchases better than ever. But before we get into what's new, let's quickly review how developers work with StoreKit to add in-app purchases to their apps today. Currently, if I'm looking to update my app, either to begin selling content through StoreKit, or to add new content to sell, one of the very first steps I have to take is to sign in to App Store Connect. There, I need to register my app, define my in-app purchases, and create my Sandbox accounts for testing. Only after I've taken those steps can I go back to Xcode and start writing the code to integrate StoreKit within my app.
As I'm building up my app, I'll be working with the Sandbox environment to test my in-app purchases using one of the Sandbox accounts I set up in App Store Connect. There I won't be charged as purchases are made during my testing. Additionally, when I hand off my app to be beta tested. the Sandbox environment will be continued to be used by developers working with my app. Only after I verified my app works as expected, will I release my app to the app store, where the production environment is used to back all StoreKit calls. This has worked well in the past, but we think we can do better for you, our developers. I'm excited to announce this year, with Xcode 12, we're introducing a new development and testing suite dedicated to StoreKit and in-app purchases. This will allow you to start right in Xcode to build and test your app's in-app purchases entirely locally. This is all integrated right into Xcode, so it works seamlessly with your app's development workflow. Additionally, we're introducing a brand new StoreKit test framework that will unlock the full automation testing for your StoreKit integration. This changes the entire development lifecycle for StoreKit. Now instead of starting in App Store Connect, you can start right in Xcode. Build out your StoreKit integration at the same time you're building out the rest of your app.
Add in unit UI and other automation tests to make sure the quality of your app's StoreKit integration remains high, then sign in to App Store Connect and begin using the Sandbox environment. Working with Sandbox is a critical step you need to take to make sure your app is ready to be released to your users in the App Store. It's also the environment you need to use to test out any server-to-server functionality required for your app. Additionally, we're adding a number of great enhancements to the Sandbox environment this year that my colleague Chris will go into more detail later on in the session.
Let's dive in and take a closer look at StoreKit testing in Xcode 12. The app I'm building, Fruta, is all about fruit smoothies and the feature I'm working on right now is around selling recipes for those smoothies. StoreKit is the right technology to use as those recipes are digital content I want to offer within my app. I've already configured Fruta to fetch and render those store products for the recipes. If I navigate to Store.swift, where I keep most of the store content within my app, you can see I have a list of product identifiers for all the different recipes I want to sell. Further down within the fetchedProducts function, I have a SKProductsRequest call where I'm passing in all the product identifiers from those recipes. Fruta should be ready to go for fetching and rendering those products. So let's launch it in the simulator and see what happens.
As you can see, none of my recipes are showing. But this is expected, because I've not yet configured my app or in-app purchases within App Store Connect, and by default, StoreKit is using the Sandbox environment. So I need to enable local testing within Xcode. To do that, I'll first need to define my in-app products inside my project. First, I navigate up to the file menu, create a new file.
There I'll type in StoreKit and select the StoreKit configuration file template. And I'll just create a new configuration file right inside my project. And now I'll have a place to store the metadata for all my in-app products; the recipes that my app will offer. In the bottom left-hand corner of this editor, I have the option to add StoreKit items to this file. As I select that, I'm given a choice over which type of product to add. The first option is for a consumable, which is a type of product that you can buy over and over and over again, such as lives or gems within a game. The second is for a non-consumable, which are purchased once and never expire. Lastly we have auto-renewable subscriptions where users are charged periodically for access to services or content. I'm going to choose to create a non-consumable as that makes the most sense for purchasing digital recipes. And now I need to fill out the details for the recipe I want to sell. In this case, I'm gonna choose Berry Blue as it's my favorite smoothie. The product ID is a unique identifier for this specific product within my app and it needs to match the value that my app will pass in to the StoreKit APIs. To make sure I get it right, I'm just gonna copy and paste it from Store.swift.
Next I need to set a price. Unlike in App Store Connect, where I can choose from a price tier, here I'm given the option to enter in any decimal value. This is because for StoreKit testing in Xcode the price is simply used for setting what value is returned in the SKProduct that is handed back to my app. So here I have direct control over the value and I can easily change it to make sure my app can handle any possible value returned. For now, I'm going to leave it as 99 cents. Additionally, I have the option to enable Family Sharing. This is a brand new feature we're releasing this year. For the purposes of StoreKit testing in Xcode, enabling Family Sharing will update the IsFamilySharable flag on the SKProduct. I'm going to leave that unset. Lastly, I need to give this product a localized name within my app.
I can also set a description, but for now, I'm going to leave that blank. Now that I've set up my StoreKit configuration, I need to tell Xcode to use it instead of Sandbox when launching my app. Doing that's as easy as opening up the scheme editor, and under Run Options, selecting that configuration I just created. Now when I relaunch my app, StoreKit is using the local test environment. And the SKProduct returns the metadata I've configured. Earlier I skipped setting a description for Berry Blue. But I want a description to show up and Fruta is already set up to take the localized description from the SKProduct and display it. StoreKit testing in Xcode is entirely interactive, meaning I can update the metadata from my app's products without recompiling or even relaunching. I just need to update the StoreKit configuration file to have the description I want.
And have my app re-execute the SK product requests to pull down the updated metadata.
My project already contained a StoreKit configuration that has all the recipes I will be selling, so I'm going to quickly switch over to that file and relaunch my app.
My app is already configured to take the SKProduct that we fetched and use it to create an SK payment and add it to the payment queue. To exercise that code, I just need to select one of the buy buttons.
Right here in the simulator, I get a payment sheet a lot like what my users will see. The big difference here is that I didn't need to sign in and there is no need to authenticate since this is just for testing purposes and I won't be charged. I simply select confirm and the payment goes through. Just like Sandbox or production, my app's payment transaction observer is updated as the transaction goes from purchasing to purchased. I'm even given a receipt that my app can verify. Berry Blue is now unlocked and I can navigate in and see the recipe. Now let's say you had an issue where I needed to purchase Berry Blue all over again, possibly to fix a bug or to change the experience around purchasing. Xcode makes that really easy with the new StoreKit Transaction Manager.
I see all the purchases I made in the local test environment and I have full control over them. I'm able to delete this transaction, and reset state as if the purchase never happened.
I can now buy Berry Blue again as if I'd never purchased it before.
In addition to being able to delete previous purchases, I have the ability to simulate a refund. In the case of a refund, the transaction remains in the transaction manager but is marked as refunded.
The transaction also remains in the app's receipt, but is updated to contain a cancellation date for when the refund occurred. Again, my app is informed about the refund and is able to respond immediately. If you want to make sure your app has a great experience for kids who need to get permission before making purchases, StoreKit testing in Xcode has full support for Ask to Buy. It's as easy as going back to your StoreKit configuration file and enabling Ask to Buy under the editor menu.
Now when I go to purchase a recipe within Fruta, I see the same Ask Permission dialogue that will be presented to any user who has Ask to Buy turned on for their account.
When I select "Ask," the transaction appears as pending approval within the transaction manager. And in code, my app's SKPayment transaction observer is informed that the transaction is now in a deferred state.
I can now approve or decline it. Once I approve, the previously deferred transaction is updated to a purchase state and my app updates right away to show the unlocked recipe. I also have the option to enable interrupted purchases. This will allow me to simulate the case where a user needs to take some action on their account before being able to complete a purchase. For example they may need to update details related to their account's billing information. In this case, the initial purchase will come back as failed. But once the user has taken action to resolve whatever issue caused the interruption, a new transaction for the same product will be added to the payment queue.
I've been considering changing the business model of my application to be subscription based. For one monthly price, users will have access to all the smoothie recipes instead of needing to buy them one at a time. StoreKit Testing in Xcode makes it really easy to build auto-renewable subscriptions with StoreKit. I've already created a second StoreKit configuration file that contains two different subscriptions I want to offer in my app. First, Recipes Plus, which is configured to renew at a monthly price of $2.99.
To make it even more compelling, I've set up an introductory offer of 99 cents for the first month. I've also created a Recipes Pro option, which not only unlocks all the recipes in my app, but gives subscribers access to advanced nutrition facts for each smoothie. The two subscriptions are contained in the same subscription group, enabling my app to offer upgrade options between Recipes Plus and Recipes Pro. I've already built Fruta to work with these subscriptions, so to try out that business model, I just need to switch StoreKit configurations and relaunch my app.
Here my app is displaying details about both the subscription offers, including the introductory offer on Recipes Plus. I want to make sure my app correctly handles when my subscription auto-renews, but I don't want to wait a full month to test it out. With StoreKit testing in Xcode, I have the power to speed up time. In the editor menu of my subscription configuration, I select Time Rate, and I can set one second to be one day. This will change it so we only have to wait seconds for that renewal to occur instead of an entire month.
Now that I've purchased that subscription, all the recipes are unlocked. And I won't have to wait very long for the Recipe auto-renewing subscription to automatically renew.
Earlier as I was working with the transaction manager to delete and refund purchases, my app immediately updated to revoke access to those recipes. This was made possible in iOS14 thanks to a new API we added on SKPayment transaction Observer: didRevokeEntitlementsForProduct Identifiers. To learn more about this API and all of the other new features we've added to StoreKit this year, I highly suggest you check out What's New with In-App Purchases. To enable you to authenticate the purchased content in your app, the App Store provides a digitally signed receipt. The receipt is the trusted record of purchases made by the user in your app. It's stored on the device and updated automatically by the system. It is signed so you know that it came from the App Store and was meant for your app on that device. If you want to learn more on how to verify the receipt, I recommend checking out Best Practices and What's New with In-App Purchases from 2018. But I do want to highlight some key differences you need to keep in mind when working with the receipts generated by the local Xcode StoreKit test environment. First, they are signed with a different private key than what is used for the receipts generated in the Sandbox or production environments. That means you need to use a different certificate when validating. We provide a convenient way to export that StoreKit Test Certificate into your project via the editor menu of your StoreKit configuration file. Lastly, the StoreKit Test Certificate is not part of a certificate chain. To accommodate for those differences, you should make use of the debug macro within your client-side validation code. Here you can see where my code is choosing between the StoreKit test certificate and the Apple, Inc. Root Certificate, based on that macro. Additionally, if I use open SSL for my client-side receipt validation, I would pass in the PKCS7 no chain argument, but only when building for debug. StoreKit Testing in Xcode 12 work great on all of the OS betas that we just released, both when building and running in the simulator as well as on real devices. I walked you through setting up your project StoreKit configuration, enabling the local test environment, using the transaction manager to delete and refund previous purchases, and making sure your app has a great experience for deferred or interrupted purchases, and purchases that renew automatically. But as critical is it is for you to be able to build and test your store kit integration manually, it's just as important for you to build automation that continuously tests your in-app purchases, which is why we're introducing a brand new StoreKitTest Framework that enables you in code to control the full local test environment. All the controls that you had manually are exposed inside your tests. StoreKitTest works with XCTest for extending unit and UI test coverage to your in-app purchases. Additionally, with StoreKitTest you have the ability to disable all the sheets and dialogs that would normally appear. So your tests can run to completion

