Untitled
unknown
swift
2 years ago
3.9 kB
12
Indexable
final class PaywallManager: NSObject {
static let shared = PaywallManager()
var isSubscribed: Bool {
switch Superwall.shared.subscriptionStatus {
case .active:
return true
default:
return false
}
}
/// Configures both the RevenueCat and Superwall SDKs.
///
/// Call this on `application(_:didFinishLaunchingWithOptions:)`
static func configure() {
Superwall.configure(
apiKey: Constants.superwallApiKey,
purchaseController: shared
)
Purchases.configure(withAPIKey: Constants.revenueCatApiKey)
Superwall.shared.logLevel = .error
Purchases.logLevel = .error
syncSubscriptionStatus()
}
/// Handles a deep link to open a paywall preview.
///
/// [See here](https://docs.superwall.com/v3.0/docs/in-app-paywall-previews#handling-deep-links)
/// for information on how to call this function in your app.
static func handleDeepLink(_ url: URL) {
Superwall.shared.handleDeepLink(url)
}
/// Updates the subscription status in response to customer info received from RevenueCat.
private func updateSubscriptionStatus(using customerInfo: CustomerInfo) {
if customerInfo.entitlements.active.isEmpty {
#if DEBUG
Superwall.shared.subscriptionStatus = .active
#else
Superwall.shared.subscriptionStatus = .inactive
#endif
} else {
Superwall.shared.subscriptionStatus = .active
}
}
// MARK: Sync Subscription Status
/// Makes sure that Superwall knows the customers subscription status by
/// changing `Superwall.shared.subscriptionStatus`
static func syncSubscriptionStatus() {
assert(Purchases.isConfigured, "You must configure RevenueCat before calling this method.")
Task {
for await customerInfo in Purchases.shared.customerInfoStream {
// Gets called whenever new CustomerInfo is available
let hasActiveSubscription = !customerInfo.entitlements.active.isEmpty // Why? -> https://www.revenuecat.com/docs/entitlements#entitlements
if hasActiveSubscription {
Superwall.shared.subscriptionStatus = .active
} else {
#if DEBUG
Superwall.shared.subscriptionStatus = .active
#else
Superwall.shared.subscriptionStatus = .inactive
#endif
}
}
}
}
}
// MARK: - PurchaseController
extension PaywallManager: PurchaseController {
// MARK: Handle Restores
/// Makes a restore with RevenueCat and returns `.restored`, unless an error is thrown.
/// This gets called when someone tries to restore purchases on one of your paywalls.
func restorePurchases() async -> RestorationResult {
do {
_ = try await Purchases.shared.restorePurchases()
return .restored
} catch {
return .failed(error)
}
}
// MARK: Handle Purchases
/// Makes a purchase with RevenueCat and returns its result. This gets called when
/// someone tries to purchase a product on one of your paywalls.
func purchase(product: SKProduct) async -> PurchaseResult {
do {
let storeProduct = RevenueCat.StoreProduct(sk1Product: product)
let revenueCatResult = try await Purchases.shared.purchase(product: storeProduct)
if revenueCatResult.userCancelled {
return .cancelled
} else {
return .purchased
}
} catch let error as ErrorCode {
if error == .paymentPendingError {
return .pending
} else {
return .failed(error)
}
} catch {
return .failed(error)
}
}
func purchases(_ purchases: Purchases,
readyForPromotedProduct product: RevenueCat.StoreProduct,
purchase startPurchase: @escaping StartPurchaseBlock)
{
startPurchase { _, info, error, cancelled in
if let info = info, error == nil, !cancelled {
self.updateSubscriptionStatus(using: info)
}
}
}
}
Editor is loading...