Engineering

Migrating from StoreKit 1 to StoreKit 2

While still supporting StoreKit 1

Nacho Soto
Nacho SotoOctober 24, 2022

StoreKit 1 vs. StoreKit 2

StoreKit has been with us since iPhone OS 3.0 launched in 2009. It was not without its flaws, and developers had to battle implementation and upkeep for over 12 years.

At WWDC 2021, we saw the introduction of the new StoreKit 2: a new Swift-only framework with modern async APIs. Since then, the RevenueCat team has been hard at work to support the new APIs. 

Why we support both

Using StoreKit 2 is not possible with Objective-C or if you need to support versions before iOS 15.0. So, migrating to StoreKit 2 might not be as straightforward for all apps with existing StoreKit 1 implementations.

This is another reason why using RevenueCat can vastly simplify in-app purchases. Our SDK provides abstractions that are backed by StoreKit 1 or StoreKit 2. Take, for example, the StoreProduct type:

1/// TypeAlias to StoreKit 1's Product type, called `StoreKit/SKProduct`
2public typealias SK1Product = SKProduct
3 
4/// TypeAlias to StoreKit 2's Product type, called `StoreKit.Product`
5@available(iOS 15.0, tvOS 15.0, watchOS 8.0, macOS 12.0, *)
6public typealias SK2Product = StoreKit.Product
7 
8/// Type that provides access to all of `StoreKit`'s product type's properties.
9@objc(RCStoreProduct) public final class StoreProduct: NSObject, StoreProductType {
10 
11    let product: StoreProductType

This allows users to write code once (in either Objective-C or Swift) that can run on iOS versions as far back as 11.0.

Choosing an implementation

When version 4.0.0 of our iOS SDK launched, StoreKit 2 support was still in beta and therefore was opt-in only.

Internally, the SDK uses 3 different settings:

1/// Defines when StoreKit 2 APIs may be used
2enum StoreKit2Setting {
3 
4    /// Never use SK2
5    case disabled
6 
7    /// Use SK2 (if available in the current device) only for certain APIs that provide a better implementation
8    /// For example: intro eligibility, determining if a receipt has purchases, managing subscriptions.
9    case enabledOnlyForOptimizations
10 
11    /// Enable SK2 in all APIs if available in the current device
12    case enabledForCompatibleDevices
13 

Using this abstraction, we’re able to make our tests run in both StoreKit 1 and StoreKit 2, ensuring that all APIs produce consistent results.

StoreKit 2 has been disabled by default, but we provided a way to enable it:

1Purchases.configure(
2            with: .init(withAPIKey: "api_key")
3                .with(usesStoreKit2IfAvailable: true)
4                .build()

After many months of testing, and thanks to several of our users using this in production, we stopped considering this experimental.

Even though StoreKit 2 does not provide a replacement for every single API that StoreKit 1 has, we were also recently able to disable the majority of the StoreKit 1 wrappers. This means that when StoreKit 2 support is enabled, we no longer unnecessarily have StoreKit 1 and StoreKit 2 listeners.

The future

It’s clear that Apple’s focus is now on StoreKit 2 moving forward: iOS 16 only brought improvements to StoreKit 2. We also see more reports of unreliable behavior from StoreKit 1 than StoreKit 2. For example, a common issue with StoreKit 1 is transactions not having an ID.

Additionally, some of the SDK implementations become much more accurate with StoreKit 2, like the implementation for checkTrialOrIntroDiscountEligibility.

There are also several workarounds for StoreKit 1, like properties that are marked as not-optional but that can actually return nil. These aren’t issues when using StoreKit 2.

For all these reasons, version 4.13.0 of our Purchases SDK has StoreKit 2 enabled by default. And, the best part is that RevenueCat customers don’t need to change any code.

Subscribe to our monthly newsletter

Related posts

Google Play class action developer lawsuit
Engineering

Google Play Billing Library 5.0, an overview

Everything you need to know about Google Play Billing Library 5

Rik Haandrikman

Rik Haandrikman

November 25, 2022

Engineering

How RevenueCat’s SDK team uses Release Trains

How we automate the releases of our SDKs

Cesar de la Vega

Cesar de la Vega

October 31, 2022

Stripe for In-App Purchases
Engineering

Can You Use Stripe for In-App Purchases?

Learn about when you can use Stripe and opportunities to save money on fees.

Corey Rabazinski

Corey Rabazinski

October 31, 2022

Ready to get started?

We saved 6,000+ engineering hours per year by switching to RevenueCat

Kemal Ugur, Pixery LabsKemal Ugur, Pixery Labs
Read case study