Migrating from StoreKit 1 to StoreKit 2

While still supporting StoreKit 1

Nacho Soto

Nacho Soto

PublishedLast updated

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
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
8/// Type that provides access to all of `StoreKit`'s product type's properties.
9@objc(RCStoreProduct) public final class StoreProduct: NSObject, StoreProductType {
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 {
4    /// Never use SK2
5    case disabled
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
11    /// Enable SK2 in all APIs if available in the current device
12    case enabledForCompatibleDevices

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:

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.

StoreKit 1 vs 2: 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.

In-App Subscriptions Made Easy

See why thousands of the world's tops apps use RevenueCat to power in-app purchases, analyze subscription data, and grow revenue on iOS, Android, and the web.

Related posts

How we solved RevenueCat’s biggest challenges on data ingestion into Snowflake
How we solved RevenueCat’s biggest challenges on data ingestion into Snowflake

How we solved RevenueCat’s biggest challenges on data ingestion into Snowflake

Challenges, solutions, and insights from optimizing our data ingestion pipeline.

Jesús Sánchez

Jesús Sánchez

April 15, 2024

How RevenueCat handles errors in Google Play’s Billing Library
How RevenueCat handles errors in Google Play’s Billing Library  

How RevenueCat handles errors in Google Play’s Billing Library  

Lessons on Billing Library error handling from RevenueCat's engineering team

Cesar de la Vega

Cesar de la Vega

April 5, 2024

Use cases for RevenueCat Billing

Use cases for RevenueCat Billing

3 ways you can use the new RevenueCat Billing beta today.

Charlie Chapman

Charlie Chapman

March 21, 2024

Want to see how RevenueCat can help?

RevenueCat enables us to have one single source of truth for subscriptions and revenue data.

Olivier Lemarié, PhotoroomOlivier Lemarié, Photoroom
Read Case Study