Niels Mouthaan Niels Mouthaan - 6 months ago 42
Objective-C Question

Receipt does not get updated after purchasing an automatically renewable subscription in a macOS sandbox environment

I am trying to implement StoreKit's ability to have automatically renewable subscriptions in my macOS application.

After reading dozens of pages and checking examples, I understand how everything fits together but fail to get it to work correctly.

What I am trying to do:

  1. As soon as the app starts, check if an active subscription is available by evaluating the local receipt. I'm specifically checking the unavailability of a cancellation date in any of the In-App Purchase field entries of the receipt and whether the subscription expiration date is in the future.

  2. In case no (active) subscription is available, I'm purchasing the subscription using StoreKit's APIs.

Both scenarios are working fine as this flow works perfectly when the subscription is purchased for the first time. However, the receipt does not get updated automatically after the subscription expiration date ends. I'm expecting this receipt to be updated periodically as also shown on Auto-renewing subscription and app receipt. As a result the first step described above fails because the expiration date at some point is in the history and hence, is considered expired.

Two things I find strange:

  • My SKPaymentTransactionObserver instance only gets called after purchasing the subscription (after a user explicitly buying it). It never gets called when the subscription expires and should automatically renew (as shown in the above blog post);

    • Explicitly asking my receipt (containing the IAP's expiration date) to be updated using the SKReceiptRefreshRequest API fails by calling it's request:didFailWithError: delegate method. The error object is nil so I cannot see why it fails updating.

I can share code but I have a feeling this is not related to code but instead is some kind of project/environment setting and/or behaviour I do not fully get.

Do you have any suggestions what to try?


After a few days of experimenting I changed the mechanism to use the server-side validation documented on Obviously this requires a web service running somewhere and makes your environment more complicated but at least things work in a more stable (and secure) way.