EasyApp

内购

了解 EasyAppSwiftUI 应用内购买模块

inapppurchases

内购模块

InAppPurchases 模块提供了完善的应用内购买解决方案,支持多种实现方式,包括 RevenueCat 和 StoreKit2 两套完整的订阅管理系统。

我们后续提供更多精美内购页面UI实现,敬请期待。

模块结构

InAppPurchases/
├── View/
│   ├── InAppPurchasesView.swift                    # 主入口页面
│   ├── CustomAPWithRevenueCatPaywallView.swift     # RevenueCat完全自定义
│   ├── ASemiCustomWithRevenueCatPaywallView.swift  # RevenueCat半自定义
│   └── CustomStoreKit2PaywallView.swift            # StoreKit2完全自定义
└── TestPremium/
    ├── TestRequirePremium.swift                    # 测试Premium访问控制
    └── TestActionGoPaywall.swift                   # 测试Paywall触发

四种内购实现方案

1. 完全自定义 RevenueCat Paywall

使用 RevenueCat SDK API 实现完全自定义的付费墙界面:

核心特性:

  • 自动计算订阅套餐间的节省金额
  • 年度订阅显示月均价格
  • 集中化的价格逻辑处理
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 {
                    // 订阅信息显示
                    if let productTitle = authManager.storeProduct?.localizedTitle,
                       let entitlement = authManager.customerInfo?.entitlements[
                        Constants.RevenueCat.entitlementID], entitlement.isActive {
                        SubscriptionInfoView(
                            productTitle: productTitle,
                            expirationDate: entitlement.expirationDate
                        )
                    }
                    
                    // 套餐选择界面
                    if let offerings = revenueCatManager.currentOfferings,
                       let currentOffering = offerings.current {
                        // 渲染套餐选择UI
                    }
                }
            }
        }
    }
}

2. 半自定义 RevenueCat Paywall

使用 RevenueCat 的 .paywallFooter() API,允许自定义设计内容:

struct ASemiCustomWithRevenueCatPaywallView: View {
    var body: some View {
        // 自定义顶部内容
        CustomPaywallContent()
            .paywallFooter()  // RevenueCat 提供的购买按钮逻辑
    }
}

3. 完全自定义 StoreKit2 Paywall

使用 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 {
                    // 当前订阅状态
                    if let productTitle = authManager.storeKitProduct?.displayName,
                       let transaction = authManager.storeKitTransaction {
                        SubscriptionInfoView(
                            productTitle: productTitle,
                            expirationDate: transaction.expirationDate
                        )
                    }
                    
                    // 产品列表
                    ForEach(storeKit2Manager.products, id: \.id) { product in
                        ProductView(
                            product: product,
                            isSelected: selectedProduct?.id == product.id
                        ) {
                            selectedProduct = product
                        }
                    }
                }
            }
        }
    }
}

4. RevenueCatUI PaywallView

直接使用 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 访问控制

1. 声明式访问控制

使用 .requirePremium() 修饰符保护需要订阅的内容:

struct TestRequirePremium: View {
    @EnvironmentObject private var authManager: AuthManager
    
    var body: some View {
        VStack {
            Text("这是需要Premium访问的内容")
                .requirePremium(
                    subscriptionType: .storeKit2,
                    sheetOrFullScreenCover: .fullScreenCover,
                    onCancelPaywall: {
                        print("用户取消了订阅")
                    },
                    onPaySuccess: {
                        print("订阅成功")
                    }
                )
        }
    }
}

2. 动作触发式访问控制

通过按钮点击等操作触发订阅检查:

struct TestActionGoPaywall: View {
    @EnvironmentObject private var authManager: AuthManager
    
    var body: some View {
        VStack {
            // RevenueCat 实现
            Button("使用RevenueCat付费墙") {
                authManager.actionGoPaywall(
                    subscriptionType: .revenueCat,
                    sheetOrFullScreenCover: .sheet
                ) {
                    // 用户有订阅权限时执行的操作
                    print("执行Premium功能")
                }
            }
            
            // StoreKit2 实现
            Button("使用StoreKit2付费墙") {
                authManager.actionGoPaywall(
                    subscriptionType: .storeKit2,
                    sheetOrFullScreenCover: .fullScreenCover
                ) {
                    // 用户有订阅权限时执行的操作
                    print("执行Premium功能")
                }
            }
        }
    }
}

核心功能特性

1. 双重订阅系统支持

  • RevenueCat - 功能丰富的订阅管理平台
  • StoreKit2 - Apple原生的订阅API
  • 可以根据项目需求选择其中一种

2. 价格计算和显示

  • 自动计算不同套餐间的节省金额
  • 年度订阅显示月均价格
  • 支持多币种和本地化价格显示

3. 订阅状态管理

  • 实时显示当前订阅状态
  • 支持恢复购买功能

4. 用户体验优化

  • 庆祝动画(Confetti效果)
  • 触觉反馈
  • 加载状态指示
  • 错误处理和重试机制

5. 灵活的展示方式

  • Sheet 弹窗模式
  • FullScreenCover 全屏模式

管理器集成

RevenueCat 管理器

@EnvironmentObject private var revenueCatManager: RevenueCatManager

// 获取订阅产品
let offerings = revenueCatManager.currentOfferings
let packages = offerings?.current?.availablePackages

// 购买处理
try await revenueCatManager.purchase(package: selectedPackage)

StoreKit2 管理器

@EnvironmentObject private var storeKit2Manager: StoreKit2Manager

// 获取产品列表
let products = storeKit2Manager.products

// 购买处理
try await storeKit2Manager.purchase(product: selectedProduct)

测试和调试

模块提供了完整的测试组件:

  1. 测试Premium访问 - 验证访问控制逻辑
  2. 测试Paywall触发 - 验证付费墙展示逻辑
  3. 模拟购买流程 - 沙盒测试

在开发阶段,内购都是在沙盒中进行测试的。进行购买时,不会真正扣费。

请使用真机进行测试,不要使用模拟器。

  • 首先我们需要在 App Store Connect 的 Users and Access 创建一个沙盒测试账号

如果您已经有测试账号按照如下图所示:

addSandboxTestAcc

点击+按钮, 来创建一个沙盒测试账号,

如果您没有测试账号, 第一次创建,请按照如下图所示:

addSandboxTestAcc2

在后续弹窗中输入您的测试账号相关信息,然后点击Create按钮保存即可。

addSandboxTestAcc3

  • 真机运行App,内购测试

如何实时查看订阅数据呢?

回到RevenueCat的Dashboard页面, 您可以看到您的所有订阅信息。

沙盒环境下,您需要打开Sandbox data 开关。

paySuccess

原生 StoreKit2 收入,需要到App Store Connect 查看。一般数据会有延迟,通常为 N+1 天。

本地化支持

  • 多语言价格显示
  • 本地化的错误消息
  • 区域化的货币格式

通过 InAppPurchases 模块,您可以快速实现专业级的应用内购买功能,支持多种技术方案和展示方式,满足不同应用场景的需求。

更多学习资料,请参考:

Last updated on