You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS IAP技术问询:如何区分恢复购买但未购该项目的状态

How to Validate "Never Purchased" After an IAP Restore Trigger

Great question—this is a common edge case when handling in-app purchase restore flows, and you don’t need to track overly complex state like "paymentQueue wasn’t called before now" to make this work. Let’s break down a clean, reliable approach based on the callback behavior you described:

Core Callback Behavior Recap

First, let’s formalize the callback flow you noted to ensure we’re aligned:

  • For users who have purchased the IAP: You’ll get two distinct callback phases:
    1. One paymentQueue(_:updatedTransactions:) callback per restored transaction (with the .restored state).
    2. A final paymentQueueRestoreCompletedTransactionsFinished(_:) callback once all restored transactions are processed.
  • For users who never purchased the IAP: You’ll only get the paymentQueueRestoreCompletedTransactionsFinished(_:) callback—no prior .restored transaction callbacks.

Step-by-Step Validation Logic

Here’s how to translate this into code logic to confirm a "never purchased" result:

  1. Track restore session state
    When you trigger the restore operation (e.g., when the user taps a "Restore Purchases" button), initialize two boolean flags:

    var isInRestoreFlow = false
    var didRestoreAnyTransactions = false
    

    Set isInRestoreFlow = true right before calling SKPaymentQueue.default().restoreCompletedTransactions().

  2. Update flags during transaction callbacks
    In your paymentQueue(_:updatedTransactions:) method, whenever you handle a .restored transaction, set didRestoreAnyTransactions = true:

    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        for transaction in transactions {
            switch transaction.transactionState {
            case .restored:
                didRestoreAnyTransactions = true
                // Handle the restored purchase (e.g., unlock content)
                queue.finishTransaction(transaction)
            // Handle other states (.purchased, .failed, etc.) as needed
            default:
                break
            }
        }
    }
    
  3. Validate the "never purchased" result in the finish callback
    When the paymentQueueRestoreCompletedTransactionsFinished(_:) callback fires, check your flags:

    func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
        defer {
            // Reset flags to clean up the restore session
            isInRestoreFlow = false
            didRestoreAnyTransactions = false
        }
        
        guard isInRestoreFlow else { return } // Ignore if this isn't part of an intentional restore
        
        if !didRestoreAnyTransactions {
            // This is your "never purchased" case!
            // Show feedback to the user (e.g., "No purchases found to restore")
        } else {
            // At least one purchase was restored—handle success state
        }
    }
    

Why This Works (And Why You Don’t Need Complex State Tracking)

This approach leverages the inherent order of the StoreKit callbacks:

  • If there are no purchases to restore, StoreKit skips sending .restored transaction callbacks entirely and goes straight to the finish callback.
  • By tracking whether any .restored events were received during the active restore flow, you can definitively confirm the "never purchased" outcome without needing to track obscure timing-based states like "paymentQueue wasn’t called before the finish callback."

Key Notes

  • Always reset your flags in the defer block (or after processing the finish callback) to avoid state leaks between different restore sessions.
  • Make sure to handle transaction errors (e.g., .failed state) in updatedTransactions—if a restore fails for network reasons, you’ll still get the finish callback, but you’ll want to distinguish that from a genuine "never purchased" result.

内容的提问来源于stack exchange,提问作者Martin Mlostek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:32:12