I have found success calling Purchases.configure, and Purchases.shared.getCustomerInfo within my widgets’ TimelineProvider.timeline() functions. I do configure Purchases to use the shared UserDefaults as their docs recommend for iOS extensions (Chris-free’s link above).
As has been noted above, this results in a lot of calls to Purchases.configure (one per widget, per widget timeline refresh). It’s working in my test project, but it would be nice to confirm with RevenueCat staff that this isn’t unwise. I don’t see any alternative as I don’t see any place that Purchases could persist in memory between timeline() calls.
If I understand this all correctly, I shouldn’t need to call `Purhcases.configure()` from my extension, so long as I properly configure it in the main app as is described here: https://www.revenuecat.com/docs/ios-app-extensions. Is that correct? If so, calling `Purchases.shared.getCustomerInfo()` should work properly from within the App extension?
When I attempt this, I get a fatal error: Purchases has not been configured. Please call Purchases.configure().
That seems to be in direct conflict with the advice to only configure `Purchases` once. I assume I also need to configure an instance from my extension?
If I understand this all correctly, I shouldn’t need to call `Purhcases.configure()` from my extension, so long as I properly configure it in the main app as is described here: https://www.revenuecat.com/docs/ios-app-extensions. Is that correct? If so, calling `Purchases.shared.getCustomerInfo()` should work properly from within the App extension?
I see, I’ve managed to retrieve the data in my widget and thought the init of my widget’s IntentTimelineProvider would be a safer place to configure Purchases. But I’m not even sure that’s safe either since I have multiple widgets that are likely to call their own providers. Some code example from RevenueCat would be great here!
Yeah, the provider stuff can get hairy really quickly. Say I have widget A with size medium and small installed and widget B with size large and rectangular installed. When I added logging I saw that meant there were FOUR calls to getTimeline() at the same time (one for each size of each widget).
I didn’t want to put it in getTimeline() because the documentation says this:
You should only configure Purchases once, usually early in your application lifecycle.
That doesn’t describe getTimeline(), which is called multiple time in a widget lifecycle. I didn’t feel comfortable doing any of this without an example of how to do it. I have my main app determine what the subscription expiration date is and my widgets are just going off of that.
I see, I’ve managed to retrieve the data in my widget and thought the init of my widget’s IntentTimelineProvider would be a safer place to configure Purchases. But I’m not even sure that’s safe either since I have multiple widgets that are likely to call their own providers. Some code example from RevenueCat would be great here!
I’m curious however how you got this working in a widget? I’ve setup Purchases as described in this page but I’m not sure where to setup Purchases in my widget code. I’ve tried in getTimeline() but when querying customerInfo, it does not seem to get the right data.
I didn’t want to put it in getTimeline() because the documentation says this:
You should only configure Purchases once, usually early in your application lifecycle.
That doesn’t describe getTimeline(), which is called multiple time in a widget lifecycle. I didn’t feel comfortable doing any of this without an example of how to do it. I have my main app determine what the subscription expiration date is and my widgets are just going off of that.
For your second question - you really can’t call getCustomerInfo() too often - it’s totally safe to call frequently and can be a good way to check the record in situations like the one you described. Typically, you can expect the customerInfo cache to update when you call getCustomerInfo, when a purchase is made, and when purchases are restored.
Thanks kaitlin. My question was actually would it be sufficient to call customerInfo() *instead* of getCustomerInfo(). I ended up finding a way to call getCustomerInfo() that I was happy with so I ended up not using customerInfo() like I had planned.
I believe customerInfor() is just the async version of getCursomerInfo(), the latter relies on a completionHandler for when you’re not in an asynchronous piece of code.
I’m curious however how you got this working in a widget? I’ve setup Purchases as described in this page but I’m not sure where to setup Purchases in my widget code. I’ve tried in getTimeline() but when querying customerInfo, it does not seem to get the right data.
For your second question - you really can’t call getCustomerInfo() too often - it’s totally safe to call frequently and can be a good way to check the record in situations like the one you described. Typically, you can expect the customerInfo cache to update when you call getCustomerInfo, when a purchase is made, and when purchases are restored.
Thanks kaitlin. My question was actually would it be sufficient to call customerInfo() *instead* of getCustomerInfo(). I ended up finding a way to call getCustomerInfo() that I was happy with so I ended up not using customerInfo() like I had planned.
Hey @Chris-29,
Yes, you’re correct, you will call configure in both the main app and the extension! I believe there's an entry point for widgets where you have to configure the framework. We don’t have any example code or an extension within the sample app, unfortunately.
For your second question - you really can’t call getCustomerInfo() too often - it’s totally safe to call frequently and can be a good way to check the record in situations like the one you described. Typically, you can expect the customerInfo cache to update when you call getCustomerInfo, when a purchase is made, and when purchases are restored.