无法使用 StoreKit2 检测订阅过期

问题描述 投票:0回答:1

我正在为我的 SwiftUI 应用程序设计一个自动续订订阅。我能够对升级和降级到不同订阅级别以及自动续订等事件做出反应。

问题是当用户取消订阅时我没有收到更新。 取消本身发生在应用程序外部(从“设置/配置文件/订阅”或在 Xcode 中通过“管理 StoreKit 事务”),因为应用程序中没有取消按钮。

理想情况下,我只想在 UserDefaults 中为每个高级功能存储两个布尔值,以便知道是否应该将其呈现给用户。 但对于当前的问题,我正在考虑使用过期日期(将在每次续订时更新)而不是布尔值,并每次根据当前日期检查它们以查看它们是否过期。

您是否看到我是否错过了

PurchaseManager
中的某些内容而无法获得订阅取消的更新?您认为这个解决方法足以完成工作吗?

import Foundation
import StoreKit
typealias SkTransaction = StoreKit.Transaction

enum PremiumFeature: String {
    case unlimitedWallets = "unlimitedWallets"
    case unlimitedReceiptScans = "unlimitedReceiptScans"
}

@MainActor
class PurchaseManager: ObservableObject {
    static let productIds: Set<String> = Set(["plus","premium"])
    @Published var products: [Product] = []
    private var subscriptionManager: SubscriptionManager
    private var updates: Task<Void, Never>? = nil
    
    init(subscriptionManager: SubscriptionManager) {
        self.subscriptionManager = subscriptionManager
        updates = observeTransactionUpdates()
    }
    
    deinit {
        updates?.cancel()
    }
    
    func loadProducts() async throws {
        products = try await Product.products(for: PurchaseManager.productIds)
    }
    
    func purchase(_ product: Product) async throws {
        print("Purcahse initiated for \(product.id)")
        let result = try await product.purchase()
        
        switch result {
        case let .success(.verified(transaction)):
            // Successful purhcase
            await transaction.finish()
            await updatePurchasedProducts()
        case .success(.unverified(_, _)):
            // Successful purchase but transaction/receipt can't be verified
            // Could be a jailbroken phone
            break
        case .pending:
            // Transaction waiting on SCA (Strong Customer Authentication) or
            // approval from Ask to Buy
            break
        case .userCancelled:
            // ^^^
            break
        @unknown default:
            break
        }
    }
    
    func updatePurchasedProducts() async {
        for await result in SkTransaction.currentEntitlements {
            guard case .verified(let transaction) = result else {
                continue
            }

            let currentDate = Date()
            let isSubscriptionActive = transaction.expirationDate == nil || currentDate <= transaction.expirationDate!

            if transaction.revocationDate == nil && isSubscriptionActive {
                // Subscription is active
                switch transaction.productID {
                case "plus":
                    print("Plus subscription active")
                    subscriptionManager.unlimitedWallets = true
                case "premium":
                    print("Premium subscription active")
                    subscriptionManager.unlimitedWallets = true
                    subscriptionManager.unlimitedReceiptScans = true
                default:
                    print("Unknown product ID \(transaction.productID)")
                }
            } else {
                // Subscription is cancelled or expired
                switch transaction.productID {
                case "plus":
                    print("Plus subscription cancelled or expired")
                    subscriptionManager.unlimitedWallets = false
                case "premium":
                    print("Premium subscription cancelled or expired")
                    subscriptionManager.unlimitedWallets = false
                    subscriptionManager.unlimitedReceiptScans = false
                default:
                    print("Unknown product ID \(transaction.productID)")
                }
            }
            await transaction.finish()
        }
    }

    
    private func observeTransactionUpdates() -> Task<Void, Never> {
        Task(priority: .background) { [unowned self] in
            for await result in SkTransaction.updates {
                print("transaction updated observed")
                guard case .verified(let transaction) = result else {
                    continue
                }
                
                await updatePurchasedProducts()
                await transaction.finish()
            }
        }
    }
}

这是我从@main 调用它的方式

/*...*/
ContentView()
.task {
    await purchaseManager.updatePurchasedProducts()
    do {
        try await purchaseManager.loadProducts()
    } catch {
        print(error)
    }
}
/*...*/

我仅使用 Xcode 及其工具“管理 StoreKit 事务”来测试订阅,因此我不确定这是否不仅仅是该工具中的错误。

我在互联网上找到的解决此问题的另一种方法是使用计时器,但经过快速研究后发现计时器的使用时间很短且不可靠,尤其是在 1 个月的时间范围内。

另一个有效的选择是设置一个服务器,该服务器将从 AppStore 接收更新,然后与我的应用程序进行通信,但我想避免为此使用服务器。

ios xcode swiftui storekit
1个回答
0
投票

没有“订阅取消”事件。当用户取消订阅时,订阅期的剩余时间将继续,然后不会续订。

使用 StoreKit2,您所需要做的就是检查

currentEntitlements
是否有您的订阅产品。如果存在订阅产品标识符,则表明存在有效订阅(或处于宽限期内的订阅),您应该提供适当的权益。如果没有订阅产品标识符,则删除福利。

© www.soinside.com 2019 - 2024. All rights reserved.