iOS In-App Purchases

iOS In-App Purchases (StoreKit 2)

Monetizing your application is a crucial step for many developers.

Apple provides the StoreKit framework to handle secure financial transactions directly within your app.

With the recent introduction of StoreKit 2, managing products, purchases, and user entitlements in Swift has never been easier or safer.


The 4 Types of In-App Purchases

Before writing code, you must define your products in App Store Connect. There are four main types:

  1. Consumables: Items that are depleted when used and can be purchased again (e.g., extra lives in a game).
  2. Non-Consumables: Items that are bought once and unlock permanently across all devices (e.g., a "Pro Mode" feature unlock).
  3. Auto-Renewing Subscriptions: Services that charge the user on a recurring basis until cancelled (e.g., Netflix, Spotify).
  4. Non-Renewing Subscriptions: Access to a service for a limited duration that does not automatically renew.

Fetching Products

To display products to your user, you must fetch the localized prices and descriptions directly from Apple's servers using the Product IDs you defined in App Store Connect.

Fetching Products with StoreKit 2:

import StoreKit

func fetchProUpgrade() async -> Product? { do { // Provide the exact Product ID string from App Store Connect let products = try await Product.products(for: ["com.intricatedevo.app.promode"]) return products.first } catch { print("Failed to fetch product from Apple: (error)") return nil } }


Purchasing a Product

When the user taps a "Buy" button, you initiate the purchase flow.

StoreKit takes over, authenticates the user with Face ID or Touch ID, and processes the payment securely.

Handling a Transaction:

import StoreKit

func purchase(product: Product) async { do { let result = try await product.purchase() switch result { case .success(let verification): // The purchase was successful! // StoreKit 2 automatically handles cryptographic receipt validation for you. print("Purchase successful!") case .userCancelled: print("User cancelled the purchase prompt.") case .pending: print("Purchase is pending (e.g., waiting for parental approval).") @unknown default: break } } catch { print("Purchase failed with error: (error)") } }


Managing Entitlements

For non-consumables and subscriptions, you must continuously check if the user is entitled to the premium features every time they open the app.

With StoreKit 2, you simply iterate over Transaction.currentEntitlements to unlock the app's features automatically.


Exercise

Which type of In-App Purchase is best suited for selling an ad-free "Pro Mode" that the user only pays for once?