I have a question about our in-app purchase flow because it was rejected by Apple.
Because we don’t know if the user has a valid subscription, we have to fetch the receipt first which leads to the iTunes Store password prompt (which is the normal behavior as we understand correctly in the not production environment). Then the validation comes and, depending on the result, we show the auto-renewing subscription page or we pass the requested action.
Our flow is:
Now Apple has commented in their rejection that they don't see the auto-renewing subscription page. Instead, they got the password prompt from iTunes Store.
As we understand correctly, the password prompt is the normal behavior in a not production environment but Apple seems to not expect this behavior. We changed nothing in the way how we fetch the receipt.
We're using SwiftyStoreKit for an easy handling. This is our code:
SwiftyStoreKit.fetchReceipt(forceRefresh: false) { result in
switch result {
case .success(let receiptData):
let encryptedReceipt = receiptData.base64EncodedString(options: [])
Log.info("Fetch receipt success")
//further code to send the receipt to our server
case .error(let error):
observer.send(error: error.localizedDescription)
}
}
Is our flow incorrect or how can we validate if the user has a valid subscription without fetching the receipt? We're a bit confused here. Can someone can give us any advice here?
Your current flow doesn't give a very good user experience; they start your app and see an iTunes account password prompt without any context as to why it is appearing.
I would suggest you adopt a process similar to the following:
Alternatively, check to see if the local receipt exists before attempting to refresh it. If the receipt doesn't exist then it is likely that the user will be prompted for an iTunes password:
if let receiptDataURL = appStoreReceiptURL,
let _ = try? Data(contentsOf: receiptDataURL) {
SwiftyStoreKit.fetchReceipt(forceRefresh: false) { result in
switch result {
case .success(let receiptData):
let encryptedReceipt = receiptData.base64EncodedString(options: [])
Log.info("Fetch receipt success")
//further code to send the receipt to our server
case .error(let error):
observer.send(error: error.localizedDescription)
}
}
} else {
// Display purchase/restore interface
}