Flare is a lightweight, developer-friendly Swift framework that simplifies working with in-app purchases

Hello Swift community :waving_hand:

I'd like to introduce Flare - a modern, lightweight Swift framework that simplifies working with in-app purchases and subscriptions across all Apple platforms.


Background:

We have a production iOS app with a deployment target of iOS 13, which means we needed to support both StoreKit 1 and StoreKit 2 simultaneously.

StoreKit 2 brought a lot of improvements async/await API, better transaction handling, improved subscription management but it's only available starting from iOS 15. For users on iOS 13 and 14, we still had to fall back to the original StoreKit 1 delegate-based API.

This created a familiar but frustrating situation:

  • Two completely different APIs to maintain in parallel

  • Conditional if #available(iOS 15, *) checks scattered across the codebase

  • Duplicated business logic for purchases, restore, and transaction handling

  • A growing gap between what newer users experienced and what older devices could support

We wanted a single, clean abstraction that would let us write purchase logic once and have it work correctly regardless of the OS version underneath.


Flare provides a unified API that internally handles the StoreKit version selection at runtime. You write modern async/await code once, and Flare routes it to the correct StoreKit implementation based on the device's OS version.

swift

// Same call on iOS 13 (StoreKit 1) and iOS 15+ (StoreKit 2)
let products = try await Flare.shared.fetch(productIDs: ["com.app.premium"])
let transaction = try await Flare.shared.purchase(product: products.first!)
Flare.shared.finish(transaction: transaction, completion: nil)

No #available checks. No duplicated logic. No version-specific branching in your feature code.

For features that are only meaningful on iOS 15+, Flare exposes them cleanly and handles the availability check internally so your call sites stay readable and consistent.

Purchase Types

Flare supports the full range of StoreKit product types:

Consumables & Non-Consumables

let products = try await Flare.shared.fetch(productIDs: ["com.app.coins", "com.app.premium"])
let transaction = try await Flare.shared.purchase(product: products.first!)
Flare.shared.finish(transaction: transaction, completion: nil)

Subscriptions

let transaction = try await Flare.shared.purchase(product: subscriptionProduct)
Flare.shared.finish(transaction: transaction, completion: nil)

Promotional & Introductory Offers

let transaction = try await Flare.shared.purchase(
    product: product,
    promotionalOffer: offer
)

Retry & Restore

Restoring previous purchases is a single call:

try await Flare.shared.restore()

Transaction updates are observed via a simple callback:

Flare.shared.addTransactionObserver { result in
    switch result {
    case let .success(transaction): handleTransaction(transaction)
    case let .failure(error): print("Error: \(error)")
    }
}

FlareUI

Flare ships with FlareUI — a separate library of ready-to-use SwiftUI and UIKit components for displaying products and paywalls with zero boilerplate.

SwiftUI:

SubscriptionsView(ids: ["com.app.monthly", "com.app.yearly"])

UIKit:

let vc = SubscriptionsViewController(ids: ["com.app.subscription"])
present(UINavigationController(rootViewController: vc), animated: true)

Repository

It supports iOS, macOS, tvOS, watchOS, and visionOS, and is designed to be easy to integrate, audit, and extend.

Repository: https://github.com/space-code/flare

If Flare saves you time on your next project, consider giving it a :star: on GitHub - it helps a lot with visibility and encourages continued development.

Thanks for reading, and happy shipping! :rocket:

1 Like