Migrate from SwiftyStoreKit

How to migrate your app using SwiftyStoreKit to Apphud Services.

Migrate your SwiftyStoreKit app to Apphud

SwiftyStoreKit is a great option to enter the world of iOS In-App Purchases. Apphud is more than just making a purchase and validating receipts.

  • Analytics - View key subscription metrics in our dashboard and charts, like MRR, Subscriber Retention (Cohorts), Churn rate, ARPU, Trial Conversions, Proceeds, Refunds, and more with exceptional accuracy.
  • Experiments (A/B Testing) - Test different In-App Purchases and paywalls. Run experiments to find the best combination of prices and purchase screen parameters that maximize ROI.
  • Paywalls - Operate with your products in more convenient way.
  • Integrations - Send subscription events to your favorite third-party platforms with automatic currency conversion. Choose from 18 integrations, including AppsFlyer, Adjust, Branch, Firebase, Amplitude, Mixpanel, OneSignal, Facebook, TikTok, and more.
  • Rules - Automatically re-engage your customers using in-app interactions and push notification campaigns.
  • Cross-Platform - iOS/Mac, Android, Flutter, React Native support.

1. SDK Initialization

Initialize Apphud SDK using your API Key:

Apphud :

import ApphudSDK

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
  
    Apphud.start(apiKey: "YOUR_API_KEY")
    return true
}

SwiftyStoreKit :

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    // see notes below for the meaning of Atomic / Non-Atomic
    SwiftyStoreKit.completeTransactions(atomically: true) { purchases in
        for purchase in purchases {
            switch purchase.transaction.transactionState {
            case .purchased, .restored:
                if purchase.needsFinishTransaction {
                    // Deliver content from server, then:
                    SwiftyStoreKit.finishTransaction(purchase.transaction)
                }
                // Unlock content
            case .failed, .purchasing, .deferred:
                break // do nothing
            }
        }
    }
    return true
}

Migration

Replace SwiftyStoreKit's completeTransactions() method with the Apphud SDK's start() method. If you have a live app with subscriptions or non-renewing purchases, you may want to migrate all your existing and historical data to Apphud. You can use migratePurchasesIfNeeded{} method. For more information please follow Data Migration Guide .

2. Load Products

At Apphud, paywalls are used to obtain products. All products of your payment screen are stored on a separate paywall. You can make multiple paywalls for multiple payment screens. Configure paywalls in Apphud Dashboard > Product Hub > Paywalls.

Apphud :

// To get notified when paywalls are ready to use, use
// paywallsDidLoadCallback – when it’s called,
// paywalls are populated with their SKProducts.
    Apphud.paywallsDidLoadCallback { (paywalls) in
       // retrieve current paywall with identifier
       if let paywall = paywalls.first(where: { $0.identifier == "currentPaywallIdentifier" in
           self.products = paywall.products
         })
    }

SwiftyStoreKit :

SwiftyStoreKit.retrieveProductsInfo(["com.test.purchase1"]) { result in
    if let product = result.retrievedProducts.first {
        let priceString = product.localizedPrice!
        print("Product: \(product.localizedDescription), price: \(priceString)")
    }
    else if let invalidProductId = result.invalidProductIDs.first {
        print("Invalid product identifier: \(invalidProductId)")
    }
    else {
        print("Error: \(result.error)")
    }
}

Migration

Configure products and paywalls in Apphud Dashboard > Product Hub > Paywalls, then replace retrieveProductsInfo() in SwiftyStoreKit with paywallsDidLoadCallback{}. This callback is called when paywalls are populated with their StoreKit products. Callback is called immediately if paywalls are already loaded.

3. Make Purchase

Apphud :

// Initiates purchase of `ApphudProduct` object from your `ApphudPaywall` 
// and automatically submits App Store Receipt to Apphud.
Apphud.purchase(product) { (result) in
       if result.error == nil {
          // purchase successfully done
       }
}

SwiftyStoreKit :

SwiftyStoreKit.purchaseProduct("com.musevisions.SwiftyStoreKit.Purchase1", quantity: 1, atomically: true) { result in
    switch result {
    case .success(let purchase):
       // purchase successfully done
    case .error(let error):
       // purchase faild 
    }
}

Migration

Replace SwiftyStoreKit’s purchaseProduct() with Apphud.purchase() method. Pass an ApphudProduct model as a parameter.

4. Check Availability Status

Apphud automatically verifies all receipts. You don't need any local receipt validation.

Apphud :

// Returns `true` if user has active subscription 
// or non renewing purchase (lifetime).
if Apphud.hasPremiumAccess() {
  // user have active purchase
}

SwiftyStoreKit :

// there is no single сhecking method
// you should track the status by yourself
let appleValidator = AppleReceiptValidator(service: .production, sharedSecret: "your-shared-secret")
SwiftyStoreKit.verifyReceipt(using: appleValidator) { result in
    switch result {
    case .success(let receipt):
        let productId = "my_product_identifier"
        // Verify the purchase of Consumable or NonConsumable
        let purchaseResult = SwiftyStoreKit.verifyPurchase(
            productId: productId,
            inReceipt: receipt)
            
        switch purchaseResult {
        case .purchased(let receiptItem):
            print("\(productId) is purchased: \(receiptItem)")
        case .notPurchased:
            print("The user has never purchased \(productId)")
        }
    case .error(let error):
        print("Receipt verification failed: \(error)")
    }
}

Migration

Use Apphud.hasPremiumAccess() to determine whether or not a user has access to your paid features. You can use Apphud.subscriptions() and Apphud.nonRenewingPurchases() to get detailed information about subscriptions or non-renewing purchases.

5. Restore Purchases

Apphud :

// Basically it just sends current App Store Receipt to Apphud 
// and returns subscriptions info.
Apphud.restorePurchases { _, _, _ in
    if Apphud.hasPremiumAccess() {
       // user have active purchase
    }
}

SwiftyStoreKit :

SwiftyStoreKit.restorePurchases(atomically: true) { results in
    if results.restoreFailedPurchases.count > 0 {
        print("Restore Failed: \(results.restoreFailedPurchases)")
    }
    else if results.restoredPurchases.count > 0 {
        print("Restore Success: \(results.restoredPurchases)")
    }
    else {
        print("Nothing to Restore")
    }
}

Migration

Replace SwiftyStoreKit’s restorePurchases{} with Apphud.restorePurchases{} method.

6. Promoted In-App Purchases

Apphud handles promoted in-app purchases initiated directly through the App Store page using ApphudDelegate method.

Apphud :

import ApphudSDK

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

    Apphud.setDelegate(self)
}

func apphudShouldStartAppStoreDirectPurchase(_ product: SKProduct) -> ((ApphudPurchaseResult) -> Void) {
    // manage your UI here, show a progress hud, etc.
    let callback : ((ApphudPurchaseResult) -> Void) = { result in 
        // check the result, hide a progress hud, etc.
    }
    return callback
}

SwiftyStoreKit :

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
  
  SwiftyStoreKit.shouldAddStorePaymentHandler = { payment, product in
    // return true if the content can be delivered by your app
    // return false otherwise
}

Migration

Replace SwiftyStoreKit’s shouldAddStorePaymentHandler with apphudShouldStartAppStoreDirectPurchase{} delegate method. You must return a callback block which will be called when payment is finished. If you don't implement this method or return nil a payment will not start.

7. Migrate Existing Subscribers

This way of migration means syncing existing purchases from the app at the first launch. When an existing user updates the app with Apphud SDK onboard, purchases migration should be initiated by the developer. You should do this just once for your paid users. Store flag in your app after the method is called.

// hasPurchases - is your own boolean value indicating that current user is paying user.
if hasPurchases {    
    Apphud.migratePurchasesIfNeeded {_, _, _ in}     
}

8. Set up App Store Server Notifications

It is required to set up Server Notifications in order to get data in real-time. If you have user receipts stored on your backend, you can contact us to import them.