SwiftUI 4中refundRequestSheet完成按钮无响应问题求助(iOS16.1+)
Hey, I’ve dealt with exactly this kind of issue with SwiftUI 4’s StoreKit sheet components before—super frustrating when the Done button doesn’t trigger the callback and you’re stuck only being able to swipe to dismiss. Let’s walk through the most likely fixes and checks:
1. Double-Check Your Transaction ID
First off, make sure the transactionID you’re passing is a valid, completed transaction ID—not a placeholder like 0 or a test value that doesn’t correspond to a real Sandbox purchase. If the ID is invalid, the sheet can enter an internal broken state where the Done button doesn’t fire properly.
- Print
viewModel.transactionIDright before presenting the sheet to confirm it’s pulled correctly from aTransactionobject (either viaTransaction.currentor a historical transaction lookup). - Avoid hardcoding
0even for testing—you need to complete a real Sandbox purchase first to get a valid ID to work with.
2. Fix the onDismiss Callback Handling
Your current onDismiss only sets viewModel.showRefundSheet = false, but this closure actually receives a Result<Void, Error>? parameter that you need to handle properly. Ignoring this can cause state conflicts between your binding and the sheet’s internal logic:
.refundRequestSheet( for: viewModel.transactionID ?? 0, isPresented: $viewModel.showRefundSheet ) { result in // First handle the result from the refund flow switch result { case .success: print("Refund completed successfully!") // Add your success logic here (e.g., update user's subscription status) case .failure(let error): print("Refund failed: \(error.localizedDescription)") case nil: print("User swiped to dismiss the sheet") } // Then update your state variable viewModel.showRefundSheet = false }
Making sure you process the result before updating the binding can resolve the button unresponsiveness in many cases.
3. Verify iOS Version Compatibility
refundRequestSheet was introduced in iOS 16, but early versions (like iOS 16.0/16.1) had several bugs with StoreKit UI components. Make sure both your simulator and physical device are running iOS 16.2 or later—Apple fixed a lot of these edge cases in subsequent minor updates.
4. Try Manual Presentation Instead of SwiftUI's Sheet
Sometimes the SwiftUI binding integration with StoreKit’s sheets can cause state conflicts. You can bypass this by using the underlying StoreKit API to present the refund request manually:
// Add this method to your viewModel func presentRefundManually() { guard let transactionID = viewModel.transactionID else { return } Task { do { try await SKStoreKitController.default().presentRefundRequest(for: transactionID) // You can listen for completion via notifications or re-check transaction status here } catch { print("Failed to present refund request: \(error)") } } }
Then trigger this method from a button in your View instead of using refundRequestSheet. This manual approach often avoids the SwiftUI layer’s state issues.
5. Check Your Sandbox Configuration
Sandbox environment quirks can also cause this behavior:
- Ensure your in-app purchase items in App Store Connect are set to "Ready to Submit" or "Approved"
- Verify your Sandbox test account hasn’t hit the refund limit (each test transaction can be refunded up to 3 times)
内容的提问来源于stack exchange,提问作者Patryk

