Swift Package: FastSpring In-App Purchase

The recent release of TableFlip v1.6 is the first one that includes a new in-app purchase (IAP) component I assembled for my projects. It’s used in TableFlip to purchase a lifetime license within the app.

With future releases, the package will support in-app purchases of consumables or individual features, too.

Find package source code here:
https://github.com/CleanCocoa/FastSpringStore

The Swift Package Index listing:
https://swiftpackageindex.com/CleanCocoa/FastSpringStore

To use this in your app, all you need is:

  • A FastSpring account with the modern backend that everyone gets. (If you are still on “Classic”, you’ll know.)
  • Create an Embedded Storefront to display a very minimal shopping UI on a HTML page. Put this on your website or another trusted source: You will have to tell FastSpring that the form is legit with a domain-based allow-list, so you should really own the source.
  • Include the package in your app and point to the URL of your self-hosted embedded storefront.
  • Bonus: if you use my Trial and Licensing package, you can quickly unlock the app after a purchase has been made. The IAP component notifies your app on success.

With that in place, you can display a dedicated purchase window inside your app that doesn’t require a large context switch to the browser to make a sale:

TableFlip's dedicated purchase window

The setup is quite short. I use a dedicated service object:

class PurchaseLicense {
    let store: FastSpringStore

    init() {
        self.store = FastSpringStore(
            storeURL: storeURL,
            purchaseCallback: { store, purchases in
                // Could have multiple purchased items, e.g. if you
                // offer in-app purchases of bundled features.
                assert(purchases.count == 1)
                guard let purchase = purchases.first else { return }

                for license in purchase.licenses {
                    // Unlock via license.licenseName & license.licenseCode, e.g.
                    // using the https://github.com/CleanCocoa/TrialLicensing package:
                    //
                    //   TrialLicensing.AppLicensing.register(
                    //       name: license.licenseName,
                    //       licenseCode: license.licenseCode
                    //   )
                }
            })
    }

    func showStore() {
        // Localize and customize the window title:
        store.showStore(title: "Purchase MyApp")
    }
}

I introduced this feature to my apps because its predecessor was a popular choice to purchase a license among WordCounter users. There, it is being picked for about 50% of license sales in total.

It appears that if the option exists, it will be used. I can’t tell whether having this option actually increases sales or not, though.

Lock App Features Behind a Paywall and Enforce the Lock in Code

Teaser image

I stumbled upon an interesting coding problem in a recent macOS project related to in-app purchases. IAP can be represented by a feature option set in code. How do you secure UserDefaults access in such a way that accessing values can be locked via the IAP available feature options? (This also applies to tiered licenses, like a “Basic” and a “Pro” feature set.)

Continue reading …