含Apple托管内容的IAP恢复未触发SKPaymentQueue回调问题
Hey there, let's break down why your updatedTransactions callback isn't firing specifically for Apple-hosted in-app purchases (IAPs), while regular non-hosted purchases restore just fine. Based on your description, the problem is isolated to the hosted content aspect—here are actionable steps to diagnose and fix this:
1. Verify Apple-Hosted Content Status in App Store Connect
The most common culprit here is incomplete or unapproved hosted content. For Apple to trigger the updatedTransactions callback during restore, the associated content must be fully prepared and validated:
- Navigate to your IAP listing in App Store Connect.
- Go to the Hosted Content section and confirm the content is:
- Successfully uploaded (no pending uploads or errors)
- Approved by Apple (not in a "pending review" state)
- Marked as Ready for Distribution
If the content isn't fully set up, Apple will skip returning the transaction inupdatedTransactions—it only triggers this callback when there's content to deliver alongside the purchase entitlement.
2. Check for Hidden Download or Entitlement Issues
Apple-hosted IAPs rely on download objects to trigger transaction updates. Try adding these additional callbacks to your observer to catch silent issues:
// Catch revoked entitlements (rare, but possible for hosted content) func paymentQueue(_ queue: SKPaymentQueue, didRevokeEntitlementsForProductIdentifiers productIdentifiers: [String]) { print("Revoked entitlements for: \(productIdentifiers)") } // Monitor download progress (if content is being delivered) func paymentQueue(_ queue: SKPaymentQueue, updatedDownloads downloads: [SKDownload]) { for download in downloads { print("Download status for \(download.contentIdentifier): \(download.state.rawValue)") } }
Even if updatedTransactions doesn't fire, these callbacks might reveal if the content is being processed or if there's an entitlement issue.
3. Confirm Transaction Observer Persistence
While you mentioned registering the observer before restoring, double-check its lifecycle:
- If your observer is tied to a view controller that could be deallocated mid-restore (unlikely since
restoreCompletedTransactionsFinishedfires, but worth ruling out), move the registration to a singleton class or your app delegate. This ensures the observer stays alive for the entire restore flow. - Re-register the observer on app launch as a best practice—Apple recommends keeping an observer active at all times to handle transactions that might complete while the app is in the background.
4. Inspect the Payment Queue After Restore Completion
When paymentQueueRestoreCompletedTransactionsFinished is called, manually check the queue for any missing transactions:
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) { print("Restore finished. Checking queue transactions:") for transaction in queue.transactions { print("Transaction ID: \(transaction.transactionIdentifier), Product: \(transaction.payment.productIdentifier)") // Check if this transaction has associated downloads (hosted content) if !transaction.downloads.isEmpty { print("Has hosted content downloads: \(transaction.downloads.count)") } } }
This will tell you if the Apple-hosted IAP transactions are actually present in the queue—sometimes they're marked as completed immediately, so they don't trigger updatedTransactions but still exist in the queue.
5. Test in a Production-like Environment
Sandbox environments can have quirks with hosted content delivery. Try testing with a TestFlight build using a real Apple ID (not a sandbox tester account) to see if the issue persists. This helps rule out sandbox-specific bugs that might be preventing the callback from firing.
内容的提问来源于stack exchange,提问作者Adam S.

