I am testing a situation when user cancels auto renewable subscription (via StoreKit->Manage Transactions window).
The problem is StoreKit2 does not provide an update when subscription was cancelled. I started using demo from apple
developer.apple.com/documentation/storekit/in-app_purchase/implementing_a_store_in_your_app_using_the_storekit_api
to test this behaviour in order to get rid of possible mistakes in my implementation, but result is the same - when user cancels subscription app does not receive any storekit events (change in renewal info, update in current entitlements, transaction status - nothing) and only after app's relaunch it fetches everything from scratch and finally updates UI.
I tried to wait for up to 20 minutes to check whether this update in transaction (subscription) status will be delivered to the app - still nothing.
So the problem, as I see it, is that if user cancels subscription and then does not relaunch the app he can continue to use the app for free for a long time.
In this regard I have several questions:
- is it expected behavior of StoreKit2? If yes - why?
- Does it happen in Test Flight mode or in production env as well?
- If it's not expected behavior then is it correct to fix it with checking (lets say once in an hour) user's current entitlements (I tried and it seems to work ok) or there are better solutions?
Important points regarding transaction updates and subscription/purchase events:
Transaction.updatesis primarily designed for new and updated transactions (purchases, successful renewals, refunds, revocations, purchases made on another device, etc.).- When a subscription simply expires (i.e., auto-renewal just didn't go through), Apple often doesn't generate a new transaction. As a result, a dedicated event in
Transaction.updatesmay not arrive at all, or may come with a significant delay. - Many developers confirm this: relying solely on
Transaction.updatesto detect the moment a subscription expires is unreliable.
The best approach is to use a combination of:
Transaction.updates— mandatory (for new transactions).Product.SubscriptionInfo.Status.updates— specifically for tracking subscription status changes (including .expired).- Periodic / event-driven calls to
refreshAll()— on app launch, when returning from the background, and when opening the paywall.
SubscriptionInfo.Status.updates is the closest thing to an "automatic event on expiration" available on the client side.