In your app’s models, you might wish to set a flag representing whether or not a user is on a paid subscription:
@Observable
class UserData {
var isPaidUser: Bool = false
}
Using subscription status
You can do this by observing the subscriptionStatus
property on Superwall.shared
. This property is an enum that represents the user’s subscription status:
switch Superwall.shared.subscriptionStatus {
case .active(let entitlements):
logger.info("User has active entitlements: \(entitlements)")
userData.isPaidUser = true
case .inactive:
logger.info("User is free plan.")
userData.isPaidUser = false
case .unknown:
logger.info("User is inactive.")
userData.isPaidUser = false
}
One natural way to tie the logic of your model together with Superwall’s subscription status is by having your own model conform to the Superwall Delegate:
@Observable
class UserData {
var isPaidUser: Bool = false
}
extension UserData: SuperwallDelegate {
// MARK: Superwall Delegate
func subscriptionStatusDidChange(from oldValue: SubscriptionStatus, to newValue: SubscriptionStatus) {
switch Superwall.shared.subscriptionStatus {
case .active(_):
// If you're using more than one entitlement, you can check which one is active here.
// This example just assumes one is being used.
logger.info("User is pro plan.")
self.isPaidUser = true
case .inactive:
logger.info("User is free plan.")
self.isPaidUser = false
case .unknown:
logger.info("User is free plan.")
self.isPaidUser = false
}
}
}
Another shorthand way to check? The isActive
flag, which returns true if any entitlement is active:
if Superwall.shared.subscriptionStatus.isActive {
userData.isPaidUser = true
}
Listening for entitlement changes in SwiftUI
For Swift based apps, you can also create a flexible custom modifier which would fire if any changes to a subscription state occur. Here’s how:
import Foundation
import SuperwallKit
import SwiftUI
// MARK: - Notification Handling
extension NSNotification.Name {
static let entitlementDidChange = NSNotification.Name("entitlementDidChange")
}
extension NotificationCenter {
func entitlementChangedPublisher() -> NotificationCenter.Publisher {
return self.publisher(for: .entitlementDidChange)
}
}
// MARK: View Modifier
private struct EntitlementChangedModifier: ViewModifier {
// Or, change the `Bool` to `Set<Entitlement>` if you want to know which entitlements are active.
// This example assumes you're only using one.
let handler: (Bool) -> ()
func body(content: Content) -> some View {
content
.onReceive(NotificationCenter.default.entitlementChangedPublisher(),
perform: { _ in
switch Superwall.shared.subscriptionStatus {
case .active(_):
handler(true)
case .inactive:
handler(false)
case .unknown:
handler(false)
}
})
}
}
// MARK: View Extensions
extension View {
func onEntitlementChanged(_ handler: @escaping (Bool) -> ()) -> some View {
self.modifier(EntitlementChangedModifier(handler: handler))
}
}
// Then, in any view, this modifier will fire when the subscription status changes
struct SomeView: View {
@State private var isPro: Bool = false
var body: some View {
VStack {
Text("User is pro: \(isPro ? "Yes" : "No")")
}
.onEntitlementChanged { isPro in
self.isPro = isPro
}
}
}
Superwall checks subscription status for you
Remember that the Superwall SDK uses its audience filters for a similar purpose. You generally don’t need to wrap your calls registering placements around if
statements checking if a user is on a paid plan, like this:
// Unnecessary
if !Superwall.shared.subscriptionStatus.isActive {
Superwall.shared.register(placement: "campaign_trigger")
}
In your audience filters, you can specify whether or not the subscription state should be considered…
…which eliminates the needs for code like the above. This keeps you code base cleaner, and the responsibility of “Should this paywall show” within the Superwall campaign platform as it was designed.