Not using RevenueCat? No problem! Superwall works out of the box without any additional SDKs.

1. Create a PurchaseController

Create a new file called RCPurchaseController.swift or RCPurchaseController.kt, then copy and paste the following:

import SuperwallKit
import RevenueCat
import StoreKit

final class RCPurchaseController: PurchaseController {
  // MARK: Sync Subscription Status
  /// Makes sure that Superwall knows the customers subscription status by
  /// changing `Superwall.shared.subscriptionStatus`
  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 {
          Superwall.shared.subscriptionStatus = .inactive
        }
      }
    }
  }

  // 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 {
      // This must be initialized before initiating the purchase.
      let purchaseDate = Date()

      let storeProduct = RevenueCat.StoreProduct(sk1Product: product)
      let revenueCatResult = try await Purchases.shared.purchase(product: storeProduct)
      if revenueCatResult.userCancelled {
        return .cancelled
      } else {
        if let transaction = revenueCatResult.transaction,
           purchaseDate > transaction.purchaseDate {
          return .restored
        } else {
          return .purchased
        }
      }
    } catch let error as ErrorCode {
      if error == .paymentPendingError {
        return .pending
      } else {
        return .failed(error)
      }
    } catch {
      return .failed(error)
    }
  }

  // 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 let error {
      return .failed(error)
    }
  }
}

As discussed in Purchases and Subscription Status, this PurchaseController is responsible for handling the subscription-related logic. Take a few moments to look through the code to understand how it does this.

2. Configure Superwall

Initialize an instance of RCPurchaseController and pass it in to Superwall.configure(apiKey:purchaseController):

let purchaseController = RCPurchaseController()

Superwall.configure(
  apiKey: "MY_API_KEY",
  purchaseController: purchaseController
)

3. Sync the subscription status

Then, call purchaseController.syncSubscriptionStatus() to keep Superwall’s subscription status up to date with RevenueCat.

That’s it! Check out our RevenueCat iOS example app for a working example of this integration.