Skip to content
This repository was archived by the owner on Oct 16, 2025. It is now read-only.

Commit 8972aeb

Browse files
authored
fix: skip upgraded transactions during subscription upgrade (#20)
## Problem When upgrading from a monthly subscription to a yearly subscription (within the same subscription group), `onPurchaseSuccess` was emitting old purchase objects first, and the correct upgraded transaction arrived only after 3-4 minutes in iOS Sandbox. - Related hyochan/react-native-iap#3054 ### Root Cause StoreKit 2's `Transaction.updates` emits **upgraded transactions** (with `isUpgraded = true`) during subscription upgrades, in addition to the new subscription transaction. These old transactions should be filtered out. ## Solution Added filtering logic to skip both revoked and upgraded transactions in `startTransactionListener()`: ```swift // Skip revoked or upgraded transactions (happens during subscription upgrades) if transaction.revocationDate != nil || transaction.isUpgraded { OpenIapLog.debug("⏭️ Skipping revoked/upgraded transaction: \(transactionId)") continue } ``` This follows Apple's official StoreKit 2 best practices from [WWDC 2021 - Meet StoreKit 2](https://developer.apple.com/videos/play/wwdc2021/10114/): > When checking if a product is purchased, ensure that the transaction's `revocationDate` equals nil (to exclude refunded transactions) and that subscriptions where a customer has upgraded don't have the `isUpgraded` flag set to true. **Apple Documentation:** - [`Transaction.isUpgraded`](https://developer.apple.com/documentation/storekit/transaction/3812954-isupgraded) - A Boolean that indicates whether the user upgraded to another subscription - [`Transaction.revocationDate`](https://developer.apple.com/documentation/storekit/transaction/3818605-revocationdate) - The date that the App Store refunded the transaction ## Changes - Added `transaction.isUpgraded` check in `startTransactionListener()` - Combined with existing `revocationDate` check for comprehensive filtering - Added debug logging for skipped transactions ## Testing - ✅ All unit tests passing (10 tests) - ✅ Swift build successful - ✅ Maintains existing functionality (subscription renewals, duplicate prevention)
1 parent 65f150f commit 8972aeb

File tree

1 file changed

+3
-3
lines changed

1 file changed

+3
-3
lines changed

Sources/OpenIapModule.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -838,9 +838,9 @@ public final class OpenIapModule: NSObject, OpenIapModuleProtocol {
838838
let transaction = try self.checkVerified(verification)
839839
let transactionId = String(transaction.id)
840840

841-
// Skip revoked transactions (happens during subscription upgrades)
842-
if transaction.revocationDate != nil {
843-
OpenIapLog.debug("⏭️ Skipping revoked transaction: \(transactionId)")
841+
// Skip revoked or upgraded transactions (happens during subscription upgrades)
842+
if transaction.revocationDate != nil || transaction.isUpgraded {
843+
OpenIapLog.debug("⏭️ Skipping revoked/upgraded transaction: \(transactionId)")
844844
continue
845845
}
846846

0 commit comments

Comments
 (0)