StoreKit 2-prenumerationer i SwiftUI: en praktisk guide

Allt du behöver för att sälja en prenumeration i en SwiftUI-app med StoreKit 2, i en liten Store-klass, plus reglerna för betalväggen som App Review kontrollerar.

Mustafa GüderGrundare, GuderTech4 min läsning
storekit-2-subscriptions-swiftui.md

StoreKit 2 gjorde köp inuti appen från en labyrint av delegater till några rader asynkron Swift. Det här är upplägget vi använder i våra egna appar: en liten Store-klass, en betalvägg och en handfull regler som håller App Review nöjd.

1. Skapa produkterna

Skapa en prenumerationsgrupp i App Store Connect och lägg till dina planer, till exempel månad och år. Anteckna produkt-ID:na. För lokala tester lägger du till en StoreKit Configuration File i Xcode med samma ID:n och väljer den i ditt scheme. Då kan du köpa, förnya och avsluta i simulatorn utan sandlådekonto.

2. En Store för hela appen

import StoreKit

@MainActor
final class Store: ObservableObject {
    @Published private(set) var products: [Product] = []
    @Published private(set) var isPro = false

    private let ids = ["com.example.pro.monthly", "com.example.pro.yearly"]
    private var updates: Task<Void, Never>?

    init() {
        // Renewals, refunds and purchases made on other devices arrive here.
        updates = Task { [weak self] in
            for await result in Transaction.updates {
                await self?.handle(result)
            }
        }
        Task {
            await loadProducts()
            await refreshEntitlements()
        }
    }

    func loadProducts() async {
        do {
            products = try await Product.products(for: ids).sorted { $0.price < $1.price }
        } catch {
            print("Could not load products: \(error)")
        }
    }

    func buy(_ product: Product) async throws {
        switch try await product.purchase() {
        case .success(let result):
            await handle(result)
        case .userCancelled, .pending:
            break
        @unknown default:
            break
        }
    }

    func restore() async {
        try? await AppStore.sync()
        await refreshEntitlements()
    }

    func refreshEntitlements() async {
        var active = false
        for await result in Transaction.currentEntitlements {
            if case .verified(let transaction) = result, transaction.revocationDate == nil {
                active = true
            }
        }
        isPro = active
    }

    private func handle(_ result: VerificationResult<Transaction>) async {
        guard case .verified(let transaction) = result else { return }
        await transaction.finish()
        await refreshEntitlements()
    }
}

Skapa den en gång, till exempel som ett @StateObject i din App, och skicka den nedåt med .environmentObject. Börja lyssna på Transaction.updates så tidigt som möjligt; annars kan köp som slutförs utanför appen missas.

3. Varför verifieringen spelar roll

Varje transaktion kommer inslagen i ett VerificationResult. StoreKit kontrollerar Apples signatur på enheten, så .verified betyder att köpet är äkta. Lås bara upp innehåll för verifierade transaktioner och anropa alltid finish() när du har levererat det.

4. En betalvägg på några rader

I iOS 17 och senare ger SubscriptionStoreView dig en komplett betalvägg som App Review gillar:

SubscriptionStoreView(groupID: "YOUR_GROUP_ID") {
    VStack(spacing: 8) {
        Text("Go Pro").font(.largeTitle.bold())
        Text("Unlimited exports and every template.")
    }
}
.storeButton(.visible, for: .restorePurchases)

Om du designar en egen, visa varje plans pris och period med product.displayPrice, länka till villkor och integritetspolicy och ta med en återställningsknapp.

5. Gratis provperioder och introduktionserbjudanden

Introduktionserbjudanden ställer du in i App Store Connect. För att visa ”Starta gratis provperiod” bara för dem som kan använda den, kontrollera behörigheten först:

let eligible = await product.subscription?.isEligibleForIntroOffer ?? false

6. Vad App Review kontrollerar i en betalvägg

  • Pris och faktureringsperiod är tydliga före köpet
  • Provperiodens längd och vad som händer efteråt
  • En fungerande knapp för att återställa köp
  • Länkar till användarvillkor och integritetspolicy
  • Inga mörka mönster, som en gömd stängknapp

Resten finns i vår lista över de vanligaste avslagen i App Store.

7. Serversidan, när du behöver den

För en app på en enhet räcker behörigheter på enheten. Om användare loggar in på flera plattformar eller om du behöver intäktsdata, lägg till App Store Server Notifications V2 i din backend så att servern får veta om förnyelser och återbetalningar direkt.

Vanliga frågor

Behöver jag fortfarande kvittovalidering med StoreKit 2?

Inte på enheten: StoreKit 2 verifierar signerade transaktioner åt dig. En server behövs bara om du delar behörigheter mellan plattformar eller konton.

Hur testar jag prenumerationer utan att betala?

Använd en StoreKit Configuration File i Xcode för lokala tester och sedan ett sandlådekonto eller TestFlight för tester hela vägen. Förnyelser i sandlådan sker i snabbare takt.

Vilken är lägsta iOS-version för StoreKit 2?

StoreKit 2 fungerar på iOS 15 och senare. SubscriptionStoreView och de andra försäljningsvyerna kräver iOS 17.

Hur mycket tar Apple av prenumerationer?

30 % som standard, 15 % för medlemmar i Small Business Program och 15 % på en prenumeration efter prenumerantens första år.

DelaXLinkedInWhatsApp
Mustafa Güder

Om skribenten

Mustafa Güder

Mustafa Güder är grundare av GuderTech och iOS-utvecklare. Efter två års studier i Australien flyttade han hem till Adana och byggde Scevia, Paw & Home och Street Legends.

Studier i Australien, 2 år Adana, Turkiet

Alla artiklar