iosin-app-purchasereceipt-validation

Is it ever necessary to refresh receipt if you are using doing server-side receipt validation?


I have created an app which has auto-renewable subscriptions.

The following is the logic that I use to know if the user has an active subscription.


The App Store review has rejected my app multiple times because the SKReceiptRefreshRequest errors out. I am unable to reproduce the error faced by the App Store review board.

While searching the internet to solve the problem, I got to know the following facts about the local receipt-

From the above 2 pieces of information, I deduce that there is no need to ever call SKReceiptRefreshRequest in production because the App Store server will provide the latest details even if the local receipt is old and the local receipt is always present in production.


In order to get my app through the App Store review, I have decided to remove the SKReceiptRefreshRequest as it gives errors in the Testflight builds and is not required in the production.

Can anyone confirm if I am correct to do this?


Solution

  • Your logic has multiple flaws:

    1) paymentQueue(_:updatedTransactions:) is called in the background and (as far as I know) updates already the local receipt. Also an app downloaded from the App Store always contains the receipt. So there is no need to call SKReceiptRefreshRequest in that method.

    2) SKReceiptRefreshRequest requires the users to input his password to allow the receipt refresh. Since you triggered the method within paymentQueue(_:updatedTransactions:), which was called in the background, I reckon this is the problem why the refresh request failed and Apple rejected your app. Nevertheless this method has its reason for being: in production you need it to allow users to restore purchases after reinstalling the app or on other devices and for debug and TestFlight builds you need it to get the latest receipt.

    3) You shouldn't send the receipt from your app to Apple's endpoint

    Warning

    Do not call the App Store server verifyReceipt endpoint from your app. You can't build a trusted connection between a user’s device and the App Store directly, because you don’t control either end of that connection, which makes it susceptible to a man-in-the-middle attack.

    Source

    How to proceed?

    I would recommend to do the following things:

    1) Do not trigger SKReceiptRefreshRequest in paymentQueue(_:updatedTransactions:)

    2) If not already done provide a "restore purchases" button in your app (which calls SKReceiptRefreshRequest)

    3) Implement local or server-to-server receipt validation