Skip to content

SwiftfulThinking/SwiftfulPurchasing

Repository files navigation

🚀 Learn how to build and use this package: https://www.swiftful-thinking.com/offers/REyNLwwH

Purchase Manager for Swift 6 💰

A reusable PurchaseManager for Swift applications, built for Swift 6. Includes @Observable support.

Pre-built dependencies*:

* Created another? Send the url in issues! 🥳

Setup

Details (Click to expand)

Create an instance of PurchaseManager:

let purchaseManager = PurchaseManager(services: any PurchaseService, logger: LogManager?)

#if DEBUG
let purchaseManager = PurchaseManager(service: MockPurchaseService(), logger: logManager)
#else
let purchaseManager = PurchaseManager(service: StoreKitPurchaseService(), logger: logManager)
#endif

Optionally add to SwiftUI environment as an @Observable

Text("Hello, world!")
    .environment(purchaseManager)

Inject dependencies

Details (Click to expand)

PurchaseManager is initialized with a PurchaseService. This is a public protocol you can use to create your own dependency.

'StoreKitPurchaseService` is included within the package, which uses the StoreKit framework to manage purchases.

let productIds = ["product.id.yearly", "product.id.monthly"]
let storeKit = StoreKitPurchaseService(productIds: productIds)
let logger = PurchaseManager(services: storeKit)

MockPurchaseService is also included for SwiftUI previews and testing.

// No activeEntitlements = the user has not purchased
let service = MockPurchaseService(activeEntitlements: [], availableProducts: AnyProduct.mocks)

// Yes activeEntitlements = the user has purchased
let service = MockPurchaseService(activeEntitlements: [PurchasedEntitlement.mock], availableProducts: AnyProduct.mocks)

Other services are not directly included, so that the developer can pick-and-choose which dependencies to add to the project.

You can create your own PurchaseService by conforming to the protocol:

public protocol PurchaseService: Sendable {
    func getAvailableProducts() async throws -> [AnyProduct]
    func getUserEntitlements() async throws -> [PurchasedEntitlement]
    func purchaseProduct(productId: String) async throws -> [PurchasedEntitlement]
    func restorePurchase() async throws -> [PurchasedEntitlement]
    func listenForTransactions(onTransactionsUpdated: @escaping @Sendable () async -> Void) async
    func logIn(userId: String, email: String?) async throws -> [PurchasedEntitlement]
}

Manage user account

Details (Click to expand)

The manager will automatically fetch and listen for purchased entitlements on launch.

Call logIn when the userId is set or changes.

You can call logIn every app launch.

purchaseManager.logIn(userId: String, email: String?) async throws
purchaseManager.logOut() async throws

Manage purchases

Details (Click to expand)

Get user's entitlements:

purchaseManager.entitlements // all purchased entitlements
purchaseManager.entitlements.active // all purchased entitlements that are still active
purchaseManager.entitlements.hasActiveEntitlement // user has at least 1 active entitlement

Make new purchase:

// Products available for purchase to this user
let products = try await purchaseManager.getAvailableProducts()

// Purchase a specific product
let entitlements = try await purchaseManager.purchaseProduct(productId: "")

// Restore purchases
let entitlements = try await restorePurchase()

About

PurchaseManager for Swift 6 w/ Observable support

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •  

Languages