Question

How to detect when subscription is expired when launching app (SwiftUI)?

  • 13 November 2023
  • 3 replies
  • 155 views

Badge

I’m playing with a sandbox account and trying to disable premium features when the entitlement is no longer present. I have tried using the following code:

Purchases.shared.getCustomerInfo { customerInfo, error in
self.isActive = customerInfo?.entitlements["premium"]?.isActive == true
}

Setting a @State-var named isActive. It does get set to true when I make a test purchase, but when I cancel the subscription I never get false. If I kill my app and relaunch it I get an updated value saying false. How do I detect that a subscription/entitlement has expired between app launches? It seems everything is cached until I kill the app and then launch it again. I want the status to be updated at least every time the app enters the foreground. Any best practice for this? 


3 replies

Userlevel 6
Badge +8

Hey @mjdragon!

This is going to depend on how often you’re calling `getCustomerInfo` - you’ll need to keep calling this method to get the latest CustomerInfo from RevenueCat’s API. In general, I would recommend calling this method every time you attempt to access premium features in the app.

It’s also worth mentioning that the SDK will cache the results for a short period of time, which is why it’s safe to call as often as you need. After ~5 minutes, the cache will be invalidated and a network call will be made instead.

If you specifically want to refresh on app foreground, you can use the `scenePhase` property in SwiftUI: https://www.hackingwithswift.com/books/ios-swiftui/how-to-be-notified-when-your-swiftui-app-moves-to-the-background

Badge

Hey @mjdragon!

If you specifically want to refresh on app foreground, you can use the `scenePhase` property in SwiftUI: https://www.hackingwithswift.com/books/ios-swiftui/how-to-be-notified-when-your-swiftui-app-moves-to-the-background

Thank you, I now have a check in scenePhase. It kind of works. If I cancel my subscription and then wait a really long time like 30 minutes after subscription is cancelled, then start my app - I still get that the subscription is active. However If I call getCustomerInfo one more time the status updates. I have now solved it by first calling getCustomerInfo on scenePhase-change, then wait 2 seconds and check getCustomerInfo one more time. I don’t know why getCustomerInfo needs to be called twice to get out of “cache mode”.

This is my code:

.onChange(of: scenePhase) { _ in
self.subscriptionStatus.refresh()

DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
self.subscriptionStatus.refresh()
}
}

All the refresh-method does is:

Purchases.shared.getCustomerInfo { customerInfo, error in
DispatchQueue.main.async {
self.isActive = customerInfo?.entitlements["premium"]?.isActive == true
}
}

Where isActive is a @Published property in a class with ObservableObject-protocol.

Badge

I’m still having problem with this. I want to show a paywall if the subscription is not active when the app launches. I have tried putting getCustomerInfo in both scenePhase and onAppear, but the status is never updated the first launch. I have to force quit the app and then launch it again. I have put a print()-statement in both scenePhase-event and onAppear, which both prints when the app launches, but it seems the getCustomerInfo is cached even long after the subscription has ended. The only way to get correct subscription status is to call getCustomerInfo multiple time when the app launches. Is there a solution to this problem? Can you force getCustomerInfo to return a non cached version at app launch?

Reply