I have added widgets to my iOS app and I would like to make this feature only accessible to "pro" users that have made a non-consumable in-app purchase.
Currently, I am doing the following:
I store an "isUnlocked" property in the Keychain after the purchase is made
I read data to be displayed in the widget and here I also query the Keychain and store whether the widget is unlocked
I have no refresh policy, but only change the widget data on a significant time change
a different view is displayed when the app is locked
Code Block func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> Void) { let entry = readContents() let timeline = Timeline(entries: [entry], policy: .never) completion(timeline) }
Code Block struct WidgetEntryView: View { let entry: Provider.Entry @Environment(\.widgetFamily) var family @ViewBuilder var body: some View { switch family { case .systemSmall: if !entry.isUnlocked { LockedWidgetView() } else if let event = entry.event { SmallWidgetEventView(event: event) } else { NoDataWidgetView() } ...
Code Block func applicationSignificantTimeChange(_ application: UIApplication) { if #available(iOS 14.0, *) { WidgetCenter.shared.reloadAllTimelines() } ...
However, 2 unexpected things happen:
the view is refreshed intraday (not only at midnight i.e. at significant time change)
sometimes the LockedWidgetView is displayed.
How can I achieve my goal of only displaying info when the user has made the in-app purchase?
Thanks in advance.
P.S. Although it would not have my preference, I would also find it acceptable if the widget is only shown as option to add once the purchase is made. In other words, I was considering changing the Widget itself:
Code Block struct MyWidget: Widget { private var supportedFamilies: [WidgetFamily] = isUnlocked() ? [.systemSmall, .systemMedium] : []
but I believe I cannot re-initialise the widget from the app when the user makes the in-app purchase, because the only refresh option that I have is
Code Block WidgetCenter.shared.reloadAllTimelines()