Swift quickstart
Add Voidhash to a native iOS app, sell a product and unlock a perk.
Install the Swift SDK in an existing iOS app, buy a product, and unlock a perk with a test purchase. The test purchase runs in development mode, so you don't need App Store Connect yet.
If another billing SDK already sells in your app, see Run in observer mode first.
Before you start
- Your app targets iOS 15 or later and builds with Xcode and a Swift 6 toolchain.
- In Studio, you have a project with a perk
premiumand a productpro_monthlythat unlocks it and has a billing duration. See Products and perks.
Set up
Install the SDK
In Xcode, choose File → Add Package Dependencies…, enter
https://github.com/voidhashcom/voidhash, and set the dependency rule to the main branch. Add the
Voidhash and VoidhashCore libraries to your app target. VoidhashCore holds the model and
error types, such as VoidhashStoreError.
To pin a commit or install with CocoaPods, see Install.
Configure the client
Configure Voidhash once, in your App initializer:
import SwiftUI
import Voidhash
@main
struct MyApp: App {
init() {
var options = VoidhashOptions()
#if DEBUG
options.dev = true
let publishableKey = "vh_pk_test_..."
#else
let publishableKey = "vh_pk_..."
#endif
Voidhash.configure(publishableKey: publishableKey, options: options)
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}Debug builds use the test publishable key and buy from a simulated store; release builds use the production key and the App Store. Copy both keys from Settings → API keys. See API keys.
configure returns at once and initializes in the background. In a UIKit app, call it from
application(_:didFinishLaunchingWithOptions:). Elsewhere, reach the client through
Voidhash.shared.
Show products and buy
Load pro_monthly and buy it when the user taps the button:
import SwiftUI
import Voidhash
import VoidhashCore
struct ContentView: View {
@State private var product: VoidhashProduct?
@State private var hasPremium = false
@State private var message: String?
var body: some View {
VStack(spacing: 16) {
Text(hasPremium ? "Premium unlocked" : "Free plan")
if let product, !hasPremium {
Button("Upgrade for \(product.displayPrice)") {
Task { await buy(product) }
}
}
if let message {
Text(message)
}
}
.task {
let products = (try? await Voidhash.shared?.getProducts()) ?? []
product = products.first { $0.slug == "pro_monthly" }
await refreshAccess()
}
}
func buy(_ product: VoidhashProduct) async {
guard let voidhash = Voidhash.shared else { return }
do {
switch try await voidhash.purchase(product: product) {
case .completed: message = nil
case .deferred: message = "Purchase received. Unlocking soon."
}
} catch let error as VoidhashStoreError where error.code == "USER_CANCELLED" {
return
} catch let error as VoidhashStoreError where error.code == "PURCHASE_PENDING" {
message = "Waiting for approval."
} catch {
message = "Purchase failed: \(error.localizedDescription)"
}
await refreshAccess()
}
func refreshAccess() async {
let person = try? await Voidhash.shared?.getCurrentPerson()
hasPremium = person?.hasActivePerk("premium") ?? false
}
}purchase(product:) shows the App Store sheet, syncs the purchase with Voidhash, and only then
finishes the transaction. It returns .completed, or .deferred when the App Store charged but
Voidhash hasn't confirmed yet. A closed sheet throws USER_CANCELLED, which isn't a failure;
PURCHASE_PENDING waits for approval, such as Ask to Buy. The SDK unlocks the perk once a deferred
or pending purchase completes. See Make and restore purchases.
Check access
refreshAccess() gates the feature on the perk, not on the purchase call returning:
let person = try await voidhash.getCurrentPerson()
let hasPremium = person?.hasActivePerk("premium") ?? falseThe SDK refreshes the person after every purchase and restore. See Check access for caching and offline behavior.
Test a purchase
Run a debug build on a device or in the Simulator. Tap Upgrade: a test confirmation sheet replaces the App Store's, and the text changes to "Premium unlocked". The purchase appears in Studio under the Test environment.
Buy through the App Store (optional)
Once the simulated purchase works, test the real App Store sheet. Sandbox accounts aren't charged.
- Connect the App Store (Help center) and map
pro_monthlyto your App Store product. - Create a Sandbox Apple Account in App Store Connect and sign in to it on a device.
- Run a release build, which uses the production key without
dev, or install it from TestFlight.
The purchase appears in Studio under Sandbox. Purchases from an Xcode StoreKit configuration file aren't sent to Voidhash. See Test purchases (Help center).
Next steps
- See a complete sample app: products, restore, a paywall with a fallback screen, sign-in and a feature flag.
- Identify users when they sign in.
- Troubleshooting when something doesn't work.
- Show a paywall designed in Studio
Something wrong or missing on this page? Tell us by email or on Discord.