Behaviour on production is different on converting a Paid iOS App to Subscriptions

  • 26 July 2021
  • 2 replies

Badge +2


I followed your tutorial to convert our Paid app to Subscriptions -

In sandbox mode everything works as expected, but in production it seems that ‘CompatibilityAccessManager’ cannot convert old users without reopening the app. So my guess is that 

‘func isActive(entitlement: String, result: @escaping ((Bool, Purchases.PurchaserInfo?) -> Void))’

works only after some delay or 2nd time in production.

I configure entitlements on ‘appDidFinishLaunch’ to grand access with this method:

‘func configure(entitlements: [BackwardsCompatibilityEntitlement], completion: ((Purchases.PurchaserInfo?) -> Void)? = nil)’.

Also I set ‘PurchasesDelegate’ to catch updates and configure UI.

When should I check ‘isActive’ state with CompatibilityAccessManager? 

Can I rely on ‘PurchasesDelegate’ or it’s better to use some timers to recheck again ‘isActive’ state?

Can we test this problem on production with promo-codes?



Best answer by cody 26 July 2021, 23:04

View original

2 replies

Userlevel 5
Badge +8

Hey @Bill Donahue ,

It sounds like maybe this is a cache issue/timing issue with CompatibilityAccessManager when calling configure immediately after configuring the normal Purchases SDK.

A workaround may be to call CompatibilityAccessManager.shared.configure once in the Purchases delegate method didReceiveUpdatedPurchaserInfo, instead of directly after configuring Purchases. That way, we know PurchaserInfo has already been returned, and it’s safe for CompatibilityAccessManager to sync the user’s receipt if necessary. Make sure this is only called once in your lifecycle, though, or it might cause a loop with refreshing PurchaserInfo.


When should I check ‘isActive’ state with CompatibilityAccessManager? 

It’s safe to call CompatibilityAccessManager.shared.isActive as often as you need, as it will use the underlying cache of Purchases. In the delegate method, you can check if an entitlement is active by checking the PurchaserInfo object directly:

purchaserInfo.isActive(entitlement: "premium_access")


I’m planning on updating PurchaserHelper with better instructions as well as support for new features. Would you mind opening an issue here where we can further discuss potential solutions?

Edit: Update 8/3/21

Since CompatibilityAccessManager requires a receipt to be synced with RevenueCat in order to work (since we rely on the originalApplicationVersion in PurchaserInfo), we just need to try and get that user's receipt synced ASAP. If it's not working from the configure method, try and get purchases synced as soon as possible.

Worst case scenario, you should communicate to your users in your paywall that if they are a previously paid user they need to restore purchases, and provide a button that calls restoreTransactions. This will immediately invalidate the current PurchaserInfo and return the latest version with the proper original purchase date and original application version, allowing CompatibilityAccessManager to grant access as expected.

Additionally, PurchasesHelper has been updated to v0.2.0 and includes better logging, a more clear ReadMe, and support for checking originalPurchaseDate as an alternative/addition to version checking. Feel free to give it a shot!

have you tested PurchasesHelper with Xcode 14? The Swift package doesn’t seem to be able to load properly from GitHub.