Post

Replies

Boosts

Views

Activity

User charged, but .userCancelled returned
Hello, Is anyone else seeing Purchase.PurchaseResult.UserCancelled, despite a successful transaction? I had a user notify me today that he: Attempted a purchase Entered payment credentials Was asked to opt in to email subscription notifications Opted In Was shown my app's "User Canceled Purchase" UI Attempted to repurchase Was alerted that he was "Already Subscribed" I have adjusted my code to check Transaction.currentEntitlements on receiving a .userCancelled result, to avoid this in the future. Is this logically sound? Here is my code - please let me know if you see any issues: func purchase(product: Product, userId: String) async throws -> StoreKit.Transaction { let purchaseUUID = UUID() let options: Set<Product.PurchaseOption> = [.appAccountToken(purchaseUUID)] let result = try await product.purchase(options: options) switch result { case .success(let verification): guard case .verified(let tx) = verification else { throw PurchaseError.verificationFailed // Show Error UI } return try await processVerified(tx) case .userCancelled: for await result in Transaction.currentEntitlements { if case .verified(let tx) = result, tx.productID == product.id, tx.revocationDate == nil { return try await processVerified(tx) } } throw PurchaseError.cancelled // Show User Cancelled UI case .pending: throw PurchaseError.pending // Show Pending UI @unknown default: throw PurchaseError.unknown // Show Error UI } } @MainActor func processVerified(_ transaction: StoreKit.Transaction) async throws -> StoreKit.Transaction { let id = String(transaction.id) if await transactionCache.contains(id) { await transaction.finish() return transaction // Show Success UI } let (ok, error) = await notifyServer(transaction) guard ok else { throw error ?? PurchaseError.serverFailure(nil) // Show Error UI } await transaction.finish() await transactionCache.insert(id) return transaction // Show Success UI } The only place the "User Cancelled Purchase" UI is displayed on my app is after the one instance of "throw PurchaseError.cancelled" above. This happened in Production, but I have also seen userCancelled happen unexpectedly in Sandbox. Thank you for your time and help.
1
1
171
May ’25