Payments
LaunchSwift’s payments feature is implemented with StoreKit 2 primitives and an @Observable state object.
ios/SwiftLaunch/Features/Payments/PaymentState.swift— purchase/loading/error state + entitlement cacheios/SwiftLaunch/Features/Payments/Services/StoreKitService.swift— StoreKit 2 adapterios/SwiftLaunch/Features/Payments/Models/PaymentModels.swift—PaymentError,StoreProduct,StoreTransaction,SubscriptionTierios/SwiftLaunch/Features/Payments/PaymentsConfig.swift— product ID mapping fromAppConfig.current.productIDsios/SwiftLaunch/Features/Payments/PaywallView.swift— paywall UIios/SwiftLaunch/Features/Payments/PremiumGate.swift— premium access gate helperios/SwiftLaunch/Features/Payments/SubscriptionState.swift— compatibility wrapper aroundPaymentState
Subscription tiers and product IDs
Section titled “Subscription tiers and product IDs”SubscriptionTier in PaymentModels.swift:
enum SubscriptionTier: String, CaseIterable, Sendable { case monthly case yearly case lifetime}Tier product IDs resolve through PaymentsConfig.Products, which reads from AppConfig.current.productIDs.
Default product IDs in AppConfig.swift:
com.swiftlaunch.pro.monthlycom.swiftlaunch.pro.annualcom.swiftlaunch.pro.lifetime
PaymentState API
Section titled “PaymentState API”@Observablefinal class PaymentState { var products: [any StoreProduct] = [] var purchasedProductIDs: Set<String> = [] var isLoading = false var error: (any Error)?
func loadProducts() async func purchase(_ product: any StoreProduct) async func restorePurchases() async func refreshEntitlements() async}PaymentState also:
- restores cached entitlements from
UserDefaults - listens for
Transaction.updatesviaStoreKitService.listenForTransactionUpdates() - refreshes entitlements when
.paymentEntitlementsDidChangeis posted
Purchase flow in current implementation
Section titled “Purchase flow in current implementation”loadProducts()requests products usingSubscriptionTier.allProductIDspurchase(_:)executes StoreKit purchase and updatespurchasedProductIDsrestorePurchases()callsAppStore.sync()and reloads entitlementsrefreshEntitlements()readsTransaction.currentEntitlementsPaywallViewdismisses automatically when purchased IDs become non-empty
Paywall UI
Section titled “Paywall UI”PaywallView is in:
ios/SwiftLaunch/Features/Payments/PaywallView.swift
It uses PaymentState directly and renders packages from loaded StoreKit products.
- The feature currently uses
StoreKitServiceProtocol(defined inStoreKitService.swift) for StoreKit abstraction. - The primary entitlement refresh method in
PaymentStateisrefreshEntitlements().