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

iOS应用内购买(IAP)功能异常求助:已购提示后无响应

Hey Kent, let's dig into why your IAP flow is stuck after that "already purchased" prompt. I spotted a few key issues in your code that are likely causing this behavior:

1. You're not finishing transactions (critical!)

The biggest problem is that you never call finishTransaction(_:) after handling a transaction. If you skip this step, the transaction stays stuck in the payment queue forever, and your app won't process subsequent state changes correctly. This is exactly why your UI stays stuck on "PLEASE WAIT..." — the system never marks the transaction as completed.

Fix: Add SKPaymentQueue.default().finishTransaction(transaction) to every case in your updatedTransactions method:

func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
    for transaction in transactions {
        switch transaction.transactionState {
        case .purchased:
            print("Transaction Successful")
            self.unlockProFeatures()
            SKPaymentQueue.default().finishTransaction(transaction) // Add this line
        case .failed:
            print("Transaction Failed: \(String(describing: transaction.error))")
            upgradeButton.isEnabled = true
            upgradeLabel.text = NSLocalizedString("UPGRADE TO PREMIUM", comment: "")
            let alert = UIAlertController(title: nil, message: transaction.error?.localizedDescription, preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "OK", style: .default))
            present(alert, animated: true)
            SKPaymentQueue.default().finishTransaction(transaction) // Add this line
        case .restored:
            print("Transaction Restored")
            self.unlockProFeatures()
            SKPaymentQueue.default().finishTransaction(transaction) // Add this line
        case .purchasing:
            print("purchasing")
        case .deferred:
            print("deferred")
        @unknown default:
            break
        }
    }
}

2. creditsLabel is undefined (causing silent failures)

Your code references creditsLabel in both .purchased and .restored cases, but there's no @IBOutlet var creditsLabel: UILabel! declared in your class. If this label isn't connected in your storyboard, this line will crash your app silently (or halt execution), preventing unlockProFeatures() from ever running.

Fix: Either add the creditsLabel IBOutlet and connect it in your storyboard, or delete those creditsLabel.text = ... lines entirely if you don't need that UI element.

3. pro property is initialized too early

Your pro property is set when the class is first initialized, not when the view loads. This means if the user just purchased premium and navigates back to this view, the pro value won't reflect the updated UserDefaults state.

Fix: Move the pro check inside viewDidLoad() to get the latest value:

override func viewDidLoad() {
    super.viewDidLoad()
    // Fetch the latest premium status when the view loads
    let pro = UserDefaults.standard.bool(forKey: "isUpgraded")
    // Setup UIView:
    if pro {
        upgradeButton.isEnabled = false
        restorebutton.isHidden = true
        upgradeLabel.text = NSLocalizedString("SUBSCRIPTION: PREMIUM", comment: "")
    } else {
        upgradeButton.isEnabled = true
        upgradeLabel.text = NSLocalizedString("UPGRADE TO PREMIUM", comment: "")
        // In App Purchase:
        print("IAP: Loading...")
        upgradeButton.isEnabled = false
        self.configureIAP()
    }
}

4. Missing invalid product ID check

You should verify if your product ID is recognized by Apple. If it's invalid, your IAP flow won't work at all.

Fix: Add a check for invalid product identifiers in your productsRequest delegate method:

func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
    print("product request")
    
    // Check for invalid product IDs
    if !response.invalidProductIdentifiers.isEmpty {
        print("Invalid product IDs found: \(response.invalidProductIdentifiers)")
        // Handle this error (e.g., show an alert to the user, double-check your App Store Connect config)
        upgradeButton.isEnabled = false
        upgradeLabel.text = NSLocalizedString("IAP UNAVAILABLE", comment: "")
        return
    }
    
    let myProduct = response.products
    for product in myProduct {
        print("product added")
        print(product.productIdentifier)
        print(product.localizedTitle)
        print(product.localizedDescription)
        print("Upgrade now! (" + product.localizedPrice() + ")")
        DispatchQueue.main.async {
            self.upgradeButton.isEnabled = true
        }
    }
}

5. Clean up redundant code

In upgradeButtonAction, you set upgradeButton.isEnabled = false twice — you can remove one of those lines to simplify the code.

After applying all these fixes, test your flow again in the sandbox. When you get the "already purchased" prompt and confirm, the .restored transaction state should trigger, unlockProFeatures() will run, and your UI will update to show the premium status correctly.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 06:52:39