Question

How frequently should I manually call getCustomerInfo in Swift?

  • 27 September 2023
  • 1 reply
  • 84 views

Badge

Hello all,

I have a question about how often I should call getCustomerInfo(). I am setting up RevenueCat in my SwiftUI application like so, based on the Magic Weather SwiftUI sample app
 

@MainActor
public class RevenueCatSingleton: NSObject, ObservableObject {
public static let shared = RevenueCatSingleton()

@Published public var customerInfo: CustomerInfo? {
didSet {
isUserPremium = customerInfo?.entitlements["plus"]?.isActive == true || customerInfo?.entitlements["mega"]?.isActive == true || customerInfo?.entitlements["epic"]?.isActive == true

if customerInfo?.entitlements["epic"]?.isActive == true {
currentUserSubscriptionLevel = .epic
} else if customerInfo?.entitlements["mega"]?.isActive == true {
currentUserSubscriptionLevel = .mega
} else if customerInfo?.entitlements["plus"]?.isActive == true {
currentUserSubscriptionLevel = .plus
}
}
}

@Published public var isUserPremium = false
@Published public var currentUserSubscriptionLevel: SubscriptionLevel

public func currentUserHasAccess(to requiredSubscriptionLevel: SubscriptionLevel) -> Bool {

if requiredSubscriptionLevel == .unknown { return true }

guard let entitlements = self.customerInfo?.entitlements else {
return false
}
return doesSubscriptionHaveAccess(entitlements: entitlements, requiredSubscriptionLevel: requiredSubscriptionLevel)
}

public func doesSubscriptionHaveAccess(entitlements: EntitlementInfos, requiredSubscriptionLevel: SubscriptionLevel) -> Bool {
switch requiredSubscriptionLevel {
case .epic:
return (entitlements["epic"]?.isActive ?? false)
case .mega:
return (
(entitlements["mega"]?.isActive ?? false)
|| (entitlements["epic"]?.isActive ?? false)
)
case .plus:
return (
(entitlements["plus"]?.isActive ?? false)
|| (entitlements["mega"]?.isActive ?? false)
|| (entitlements["epic"]?.isActive ?? false)
)
case .unknown:
return false
}
}

public override init() {
self.currentUserSubscriptionLevel = .unknown
}
}

extension RevenueCatSingleton: PurchasesDelegate {
public func purchases(_ purchases: Purchases, receivedUpdated customerInfo: CustomerInfo) {
self.customerInfo = customerInfo
}
}

 

The in applicationDidFinishLaunchingWithOptions, I run

Purchases.shared.delegate = RevenueCatSingleton.shared

 

Then in my UI Code, something like:

struct ExampleView: View {
@ObservedObject var revenueCatSingleton = RevenueCatSingleton.shared
var body: some View {
if self.revenueCatSingleton.currentUserHasAccess(to: .plus) {
Text("This is premium content!")
}
}
}

 

My question:

I may be misunderstanding, but why do I ever need to call getCustomerInfo() myself? Can’t I just rely on my own “currentUserHasAccess” function and trust that my local customerInfo is up-to-date? I’m testing in the simulator and I notice this behavior:

  • Every time the app launches, the delegate method updates customerInfo on its own
  • Every time I open the app (background → active) after 5 minutes have passed, the debug logs show the SDK refreshing customerInfo on its own (DEBUG: ℹ️ applicationWillEnterForeground, DEBUG: ℹ️ CustomerInfo cache is stale, updating from network in foreground.)
  • The delegate method is called every time I do something in the app like restore purchases or make a purchase

So if the user restores a purchase or makes a purchase during their session, customerInfo will be updated automatically. It’s also updated automatically every time they open their app.

I was considering throwing my own async call to getCustomerInfo() every time the app becomes active, but if less than 5 minutes have passed, it just grabs it from cache anyway. And the SDK is also making that call. Meaning, these manual calls to getCustomerInfo() seem redundant.

From my point of view, I can just rely on the SDK calling the delegate and never manually call getCustomerInfo(). Where is my blindspot? In what scenario would this lead to an issue for the user? 

 

The documentation states:

The SDK caches the user's subscription information to reduce your app's reliance on the network. Users who unlock entitlements will be able to access them even without an internet connection. The SDK will update the cache if it's older than 5 minutes, but only if you call getCustomerInfo(), make a purchase, or restore purchases, so it's a good idea to call getCustomerInfo() any time a user accesses premium content.


1 reply

Userlevel 4
Badge +8

It's safe to call getCustomerInfo() as often as you want. To be sure that it's always the latest info, you should refresh it before allowing access to content. if we need to refresh from the network, RevenueCat will - it's mainly to solve the case of expiring entitlements while using the app.

Reply