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.

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

Introducing ReceiptParser for Apple Platforms
Engineering

Introducing ReceiptParser for Apple Platforms

A new open-source Swift-only package for parsing StoreKit receipts locally.

Nacho Soto

Nacho Soto

February 7, 2023

The Anatomy of App Store Receipts
Engineering

App Store receipt signing certificate changes in 2023

February 7 2023 receipt signing certificate changes for the App Store

Rik Haandrikman

Rik Haandrikman

December 27, 2022

Engineering

iOS In-App Subscription Tutorial with StoreKit 2 and Swift

A step-by-step guide to a working SwiftUI sample app with subscriptions.

Josh Holtz

Josh Holtz

December 13, 2022

Want to see how RevenueCat can help?

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

Olivier Lemarie, PhotoRoomOlivier Lemarie, PhotoRoom
Read case study