SwiftyStoreKit
SwiftyStoreKit copied to clipboard
Verify Receipt fails for Apple Reviewer and keeps on rejecting app (Error: SwiftyStoreKit.ReceiptError error 2).
Bug Report
After successful purchase, Verify Receipt Works for us, but not for Apple reviewer. They are getting below error and keeps on rejecting app. (SwiftyStoreKit.ReceiptError error 2).
To Reproduce
SwiftyStoreKit.verifyReceipt(using: appleValidator) { result in
if case .success(let receipt) = result {
...
} else if case .error(let error) = result {
// Always comes here and shows error
}
Expected behavior Should come in success block and proceed further. Purchase is successful, verify receipt is failing.
Platform Information
- OS: iOS 13.5.1
- Purchase Type: auto-renewable subscription
- Environment: Sandbox and app review
- SwiftyStoreKit version: 0.13.3
Screenshots
Was there any update to this, I am having a similar issue and can not reproduce what the Apple reviewers are seeing.
It appears that a lot of developers are having the same issue with the library. I'm going to start looking into this and will get back to you as soon as I have more information. In the meantime, community investigation and support would be mighty helpful.
Iam having the same issue. Even I didn't make any changes on my code before regarding auto renewable subscription. It is working on my phone, but they are getting this error from their side. I hope this is solved the soonest
This is urgent and high priority issue. I'm getting consistent app rejections from Apple because they are unable to complete the receipt verification due to SwiftyStoreKit.ReceiptError error 2 requestBodyEncodeError.
The error occurs right after the following IAP popup during the receipt verification.
My guess is that the error is in the URLs for AppleReceiptValidator:
public enum VerifyReceiptURLType: String {
case production = "https://buy.itunes.apple.com/verifyReceipt"
case sandbox = "https://sandbox.itunes.apple.com/verifyReceipt"
}
Apple does not want the client/app to call the App Store server verifyReceipt endpoint directly. More information: https://developer.apple.com/documentation/storekit/in-app_purchase/validating_receipts_with_the_app_store
What is interesting is that the error does not occur during debug/testing and the AppStore production environment. Only during the app review Sandbox environment.
I even downgrade to SwiftyStoreKit 0.15.0 and I still get the same Apple app rejection.
@Sam-Spencer, @RomanPodymov, do you have any ideas?
This is quite a perplexing case, my only suspicion is that perhaps Apple blocks or has a different internal redirect to the sandbox verify service for its testers?
This was a critical issue for an app that needed an update, so for now I have used local validation with:
https://github.com/tikhop/TPInAppReceipt
which seems to work nicely. I haven't submitted yet but am hopeful it will go through.
Hello everybody. I get the following response from Apple when they try to verify subscriptions:
"We found that your in-app purchase products exhibited one or more bugs when reviewed on iPhone running iOS 13.5.1 on Wi-Fi."
Next Steps "When validating receipts on your server, your server needs to be able to handle a production-signed app getting its receipts from Apple's test environment. The recommended approach is for your production server to always validate receipts against the production App Store first. If validation fails with the error code "Sandbox receipt used in production," you should validate against the test environment instead."
Screenshots
I tried using SwiftyStoreKit 0.15.0 and 0.16.0, the result is identical - rejected.
I have the same problem!
I still get information from apple:
When validating receipts on your server, your server needs to be able to handle a production-signed app getting its receipts from Apple’s test environment. The recommended approach is for your production server to always validate receipts against the production App Store first. If validation fails with the error code "Sandbox receipt used in production," you should validate against the test environment instead.
Is there a workaround already? I need this urgently
@janczakb , we needed an update approved urgently, I have managed to get Apple approval now by verifying receipts locally. In other words you can use SwiftyStoreKit for everything else except receipt verification.
This is quite a perplexing case, my only suspicion is that perhaps Apple blocks or has a different internal redirect to the sandbox verify service for its testers?
This was a critical issue for an app that needed an update, so for now I have used local validation with:
https://github.com/tikhop/TPInAppReceipt
which seems to work nicely. I haven't submitted yet but am hopeful it will go through.
@wicheda Could you send me an example of use? I will be very grateful
Hi @janczakb , it depends exactly what verification logic you want. But you need to add the TPInAppReceipt library to your project as per their instructions. Then instead of calling SwiftyStoreKit.verifyReceipt , you add a new method, something like:
func validate() {
// get the receipt from SwiftyStoreKit and validate
if let receiptData = SwiftyStoreKit.localReceiptData {
do {
let receipt = try InAppReceipt.receipt(from: receiptData)
validateReceipt(receipt: receipt)
}
catch {
// error creating receipt from data?
}
}
else {
//no receipt, hence force a refresh
SwiftyStoreKit.fetchReceipt(forceRefresh: true) { result in
switch result {
case .success(let receiptData):
do {
let receipt = try InAppReceipt.receipt(from: receiptData)
self.validateReceipt(receipt: receipt)
}
catch {
print("Error validating receipt")
}
case .error(let _):
print("Error fetching receipt")
}
}
}
}
func validateReceipt(receipt:InAppReceipt) {
// Verify all at once
do {
try receipt.verify()
} catch IARError.validationFailed(reason: .hashValidation)
{
// Do smth
} catch IARError.validationFailed(reason: .bundleIdentifierVefirication)
{
// Do smth
} catch IARError.validationFailed(reason: .signatureValidation)
{
// Do smth
} catch {
// Do smth
}
// Check whether receipt contains any purchases
let hasPurchases = receipt.hasPurchases
// All auto renewable `InAppPurchase`s,
let purchases: [InAppPurchase] = receipt.autoRenewablePurchases
// all ACTIVE auto renewable `InAppPurchase`s,
let activePurchases: [InAppPurchase] = receipt.activeAutoRenewableSubscriptionPurchases
// Add your own logic here around exactly what you want to check
}
So you'll need to call validate when you want to check after a purchase / restore and at the bottom of validateReceipt add whatever checking logic your app needs. I hope that helps.
When testing my application by Apple testers, the "SwiftyStoreKit.purchaseProduct" method returns an "unknown" error
Hi @janczakb , it sounds like you more likely have issues with your products set up then, rather than this specific issue around sandbox receipt validation? SwiftyStoreKit.purchaseProduct is working for me for Apple testers (or certainly was yesterday when it was approved).
Guys, I had implemented the verified receipt from the server side and apple accepted it now....it seems now they are blocking verifying receipt from mobile
Please take a look at issue #550. Your help with this project is dearly needed! @abhirav, @sam961, @wicheda, @AdAvAn, @wimbledon
I have a different case. I'm not verifying the receipt locally, but do it in the server but got the error SwiftyStoreKit.ReceiptError error 1
when the app is reviewed by Apple testers.
I think this error is occurred in fetchReceipt()
before the app sends the receipt to the API server for validation check.
I want to know if this problem is solved?
I have a different case. I'm not verifying the receipt locally, but do it in the server but got the error
SwiftyStoreKit.ReceiptError error 1
when the app is reviewed by Apple testers. I think this error is occurred infetchReceipt()
before the app sends the receipt to the API server for validation check.
Hello,I have encountered this problem too, is it finally solved?
Why is SwiftyStoreKit.localReceiptData empty after successful purchase
I don’t see the problem on iOS, but it often appears on MacOS
`func buyProduct(product: SKProduct,orderId: String) {
SwiftyStoreKit.purchaseProduct(product, quantity: 1, atomically: true, applicationUsername: orderId, simulatesAskToBuyInSandbox: false) { [weak self] (result) in
switch result {
case .success(let purchase):
print("Purchase Success: \(purchase.productId)")
self?.uploadReceipt(receiptData: nil)
case .error(let error):
var errorStr = error.localizedDescription
switch error.code {
case .unknown: errorStr = "Unknown error. Please contact support".languageSet()
case .clientInvalid:
errorStr = "The payment is cancelled".languageSet()
case .paymentCancelled:
errorStr = "Not allowed to make the payment".languageSet()
case .paymentInvalid:
errorStr = "The purchase identifier was invalid".languageSet()
case .paymentNotAllowed:
errorStr = "The device is not allowed to make the payment".languageSet()
case .storeProductNotAvailable:
errorStr = "The product is not available in the current storefront".languageSet()
case .cloudServicePermissionDenied:
errorStr = "Access to cloud service information is not allowed".languageSet()
case .cloudServiceNetworkConnectionFailed:
errorStr = "Could not connect to the network".languageSet()
case .cloudServiceRevoked:
errorStr = "User has revoked permission to use this cloud service".languageSet()
default: print((error as NSError).localizedDescription)
}
let customerError = NSError(domain: "generateOrder", code: -1000, userInfo: [NSLocalizedDescriptionKey : errorStr])
self?.failBlock?(customerError)
}
}
}
/// upload receipt to the server
func uploadReceipt(receiptData: Data?) {
let data = (receiptData == nil) ? SwiftyStoreKit.localReceiptData : receiptData
let receiptString = data?.base64EncodedString(options: []) ?? ""
if !receiptString.isEmpty {
// ... upload receipt
}else {
print("## receipt is empty")
SwiftyStoreKit.fetchReceipt(forceRefresh: true) { [weak self] (result) in
switch result {
case .success(let receiptData):
self?.uploadReceipt(receiptData: receiptData)
case .error(let error):
self?.failBlock?(error as NSError)
}
}
}
}
`
This is my code
I think the best solution to this is to remove this buggy library and create a wrapper by yourself.
Today mine app was also rejected because of this reason.
Anyone so far got the solution? am facing the same issue. What am doing is if recceiptURL is not existing, I send a force fetch receipt to the apple server. But my build got rejected with prompting message "Receipt Error 2". The mentioned in the review message that first I need to hit to the production server and if that fails then I should go for sandbox server. Cannot produce the issue in local build and on testFlight. Anyone got the solution..?
Bug Report
After successful purchase, Verify Receipt Works for us, but not for Apple reviewer. They are getting below error and keeps on rejecting app. (SwiftyStoreKit.ReceiptError error 2).
To Reproduce
SwiftyStoreKit.verifyReceipt(using: appleValidator) { result in if case .success(let receipt) = result { ... } else if case .error(let error) = result { // Always comes here and shows error }
Expected behavior Should come in success block and proceed further. Purchase is successful, verify receipt is failing.
Platform Information
- OS: iOS 13.5.1
- Purchase Type: auto-renewable subscription
- Environment: Sandbox and app review
- SwiftyStoreKit version: 0.13.3
Screenshots
Did you get the solution? am facing the same issue.
I am facing this issue. please help me
Why is SwiftyStoreKit.localReceiptData empty after successful purchase
I don’t see the problem on iOS, but it often appears on MacOS
Did you get the solution? am facing the same issue.