In-App Purchase
Learn how to use In-App Purchase in your app

In-App Purchase Module
The InAppPurchases module provides a comprehensive in-app purchase solution, supporting multiple implementation approaches including both RevenueCat and StoreKit2 complete subscription management systems.
We will provide more beautiful in-app purchase UI implementations in the future, so stay tuned.
Module Structure
InAppPurchases/
├── View/
│ ├── InAppPurchasesView.swift # Main entry page
│ ├── CustomAPWithRevenueCatPaywallView.swift # RevenueCat fully custom
│ ├── ASemiCustomWithRevenueCatPaywallView.swift # RevenueCat semi-custom
│ └── CustomStoreKit2PaywallView.swift # StoreKit2 fully custom
└── TestPremium/
├── TestRequirePremium.swift # Test Premium access control
└── TestActionGoPaywall.swift # Test Paywall triggerFour In-App Purchase Implementation Options
1. Fully Custom RevenueCat Paywall
Implement a fully customized paywall interface using RevenueCat SDK API:
Core Features:
- Automatically calculate savings between subscription packages
- Display monthly average price for annual subscriptions
- Centralized pricing logic handling
struct CustomAPWithRevenueCatPaywallView: View {
@EnvironmentObject private var revenueCatManager: RevenueCatManager
@EnvironmentObject private var authManager: AuthManager
@State private var selectedPackage: Package?
var body: some View {
NavigationStack {
ScrollView {
VStack {
// Subscription info display
if let productTitle = authManager.storeProduct?.localizedTitle,
let entitlement = authManager.customerInfo?.entitlements[
Constants.RevenueCat.entitlementID], entitlement.isActive {
SubscriptionInfoView(
productTitle: productTitle,
expirationDate: entitlement.expirationDate
)
}
// Package selection interface
if let offerings = revenueCatManager.currentOfferings,
let currentOffering = offerings.current {
// Render package selection UI
}
}
}
}
}
}2. Semi-Custom RevenueCat Paywall
Use RevenueCat's .paywallFooter() API, allowing custom design content:
struct ASemiCustomWithRevenueCatPaywallView: View {
var body: some View {
// Custom top content
CustomPaywallContent()
.paywallFooter() // RevenueCat provided purchase button logic
}
}3. Fully Custom StoreKit2 Paywall
Implement a fully customized paywall using StoreKit2 API:
struct CustomStoreKit2PaywallView: View {
@EnvironmentObject private var storeKit2Manager: StoreKit2Manager
@EnvironmentObject private var authManager: AuthManager
@State private var selectedProduct: Product?
var body: some View {
NavigationStack {
ScrollView {
VStack {
// Current subscription status
if let productTitle = authManager.storeKitProduct?.displayName,
let transaction = authManager.storeKitTransaction {
SubscriptionInfoView(
productTitle: productTitle,
expirationDate: transaction.expirationDate
)
}
// Product list
ForEach(storeKit2Manager.products, id: \.id) { product in
ProductView(
product: product,
isSelected: selectedProduct?.id == product.id
) {
selectedProduct = product
}
}
}
}
}
}
}4. RevenueCatUI PaywallView
Directly use the standard paywall component provided by RevenueCatUI:
.sheet(isPresented: $displayPaywall) {
PaywallView(
displayCloseButton: true,
performPurchase: { package in
print("Purchase started: \(package.identifier)")
HapticsEngine.impact()
paySuccessCount += 1
syncPurchases()
return (userCancelled: false, error: nil)
},
performRestore: {
print("Restore started")
HapticsEngine.impact()
paySuccessCount += 1
syncPurchases()
return (success: true, error: nil)
}
)
}Premium Access Control
1. Declarative Access Control
Use the .requirePremium() modifier to protect subscription-required content:
struct TestRequirePremium: View {
@EnvironmentObject private var authManager: AuthManager
var body: some View {
VStack {
Text("This is Premium-only content")
.requirePremium(
subscriptionType: .storeKit2,
sheetOrFullScreenCover: .fullScreenCover,
onCancelPaywall: {
print("User cancelled subscription")
},
onPaySuccess: {
print("Subscription successful")
}
)
}
}
}2. Action-Triggered Access Control
Trigger subscription checks through button clicks and other actions:
struct TestActionGoPaywall: View {
@EnvironmentObject private var authManager: AuthManager
var body: some View {
VStack {
// RevenueCat implementation
Button("Use RevenueCat Paywall") {
authManager.actionGoPaywall(
subscriptionType: .revenueCat,
sheetOrFullScreenCover: .sheet
) {
// Actions to execute when user has subscription
print("Execute Premium feature")
}
}
// StoreKit2 implementation
Button("Use StoreKit2 Paywall") {
authManager.actionGoPaywall(
subscriptionType: .storeKit2,
sheetOrFullScreenCover: .fullScreenCover
) {
// Actions to execute when user has subscription
print("Execute Premium feature")
}
}
}
}
}Core Feature Characteristics
1. Dual Subscription System Support
- RevenueCat - Feature-rich subscription management platform
- StoreKit2 - Apple's native subscription API
- Choose one based on project requirements
2. Price Calculation and Display
- Automatically calculate savings between different packages
- Display monthly average price for annual subscriptions
- Support multi-currency and localized price display
3. Subscription Status Management
- Real-time display of current subscription status
- Support for restore purchase functionality
4. User Experience Optimization
- Celebration animations (Confetti effects)
- Haptic feedback
- Loading state indicators
- Error handling and retry mechanisms
5. Flexible Display Options
- Sheet modal mode
- FullScreenCover full-screen mode
Manager Integration
RevenueCat Manager
@EnvironmentObject private var revenueCatManager: RevenueCatManager
// Get subscription products
let offerings = revenueCatManager.currentOfferings
let packages = offerings?.current?.availablePackages
// Purchase handling
try await revenueCatManager.purchase(package: selectedPackage)StoreKit2 Manager
@EnvironmentObject private var storeKit2Manager: StoreKit2Manager
// Get product list
let products = storeKit2Manager.products
// Purchase handling
try await storeKit2Manager.purchase(product: selectedProduct)Testing and Debugging
The module provides complete testing components:
- Test Premium Access - Verify access control logic
- Test Paywall Trigger - Verify paywall display logic
- Simulate Purchase Flow - Sandbox testing
During development, in-app purchases are tested in the sandbox environment. No actual charges occur during purchases.
Please use a real device for testing, not the simulator.
- First, we need to create a sandbox test account in App Store Connect's
Users and Access
If you already have a test account, follow the image below:

Click the + button to create a sandbox test account.
If you don't have a test account and are creating one for the first time, follow the image below:

In the subsequent popup, enter your test account information and click the Create button to save.

- Run the app on a real device for in-app purchase testing
How to view subscription data in real-time?
Return to RevenueCat's Dashboard page, where you can see all your subscription information.
In the sandbox environment, you need to turn on the Sandbox data switch.

Native StoreKit2 revenue needs to be viewed in App Store Connect. Data is usually delayed, typically N+1 days.
Localization Support
- Multi-language price display
- Localized error messages
- Regionalized currency formatting
Through the InAppPurchases module, you can quickly implement professional-grade in-app purchase functionality, supporting multiple technical solutions and display methods to meet the needs of different application scenarios.
For More Learning Resources, Please Refer To:
Last updated on