inappkit-integration

star 52

Integrate InAppKit for in-app purchases in iOS/macOS SwiftUI apps. Provides subscription management, paywall UI, and purchase gating. Use when: (1) Adding in-app purchases to a SwiftUI app, (2) Creating subscription tiers (monthly/yearly/lifetime), (3) Gating features behind purchases, (4) Building custom paywall UI, (5) User asks about InAppKit integration or subscription setup.

tddworks By tddworks schedule Updated 1/15/2026

name: inappkit-integration description: | Integrate InAppKit for in-app purchases in iOS/macOS SwiftUI apps. Provides subscription management, paywall UI, and purchase gating. Use when: (1) Adding in-app purchases to a SwiftUI app, (2) Creating subscription tiers (monthly/yearly/lifetime), (3) Gating features behind purchases, (4) Building custom paywall UI, (5) User asks about InAppKit integration or subscription setup.

InAppKit Integration

InAppKit is a SwiftUI framework for in-app purchases with declarative configuration.

Quick Start

1. Add Dependency

Tuist (Project.swift):

packages: [
    .local(path: "/path/to/InAppKit"),
]

// In target dependencies:
.external(name: "InAppKit"),

2. Create StoreKit Configuration

Create AppNameStore.storekit in Resources with products:

  • Subscriptions: com.company.app.pass.monthly, com.company.app.pass.yearly
  • Non-consumable: com.company.app.pass.lifetime

3. Configure App Entry Point

import SwiftUI
import InAppKit

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .withPurchases(products: [
                    Product(AppConstants.Products.monthly),
                    Product(AppConstants.Products.yearly)
                        .withRelativeDiscount(comparedTo: AppConstants.Products.monthly, style: .percentage)
                        .withBadge("Popular", color: .orange),
                    Product(AppConstants.Products.lifetime)
                ])
                .withPaywallHeader { PaywallHeaderView() }
                .withPaywallFeatures { PaywallFeaturesView() }
                .withTerms(url: AppConstants.URLs.termsOfUse)
                .withPrivacy(url: AppConstants.URLs.privacyPolicy)
        }
    }
}

API Reference

View Modifiers (Setup)

Modifier Purpose
.withPurchases(products:) Configure products to sell
.withPaywallHeader { } Custom paywall header view
.withPaywallFeatures { } Custom features list view
.withTerms(url:) Terms of service URL
.withPrivacy(url:) Privacy policy URL

View Modifiers (Gating)

Modifier Purpose
.requiresPurchase() Gate behind any purchase
.requiresPurchase("productId") Gate behind specific product
.requiresPurchase(when: condition) Conditional gating
.requiresPurchase(whenItemCount: n, exceeds: limit) Usage-based gating

Product Definition

Product("com.app.monthly")                    // Basic product
    .withBadge("Popular", color: .orange)     // Add badge
    .withRelativeDiscount(comparedTo: "com.app.monthly", style: .percentage)
    .withMarketingFeatures(["Feature 1", "Feature 2"])
    .withPromoText("Best value!")

InAppKit.shared Properties

Property Type Description
hasAnyPurchase Bool User has any active purchase
availableProducts [Product] Loaded StoreKit products
isPurchasing Bool Purchase in progress
purchaseError Error? Last purchase error

InAppKit.shared Methods

Method Description
isPurchased(_ productId:) Check specific product
purchase(_ product:) Purchase a product
restorePurchases() Restore previous purchases

Common Patterns

Subscription Button

struct SubscriptionButton: View {
    @Binding var presentingPassSheet: Bool
    var isSubscribed: Bool

    var body: some View {
        Button {
            presentingPassSheet = true
        } label: {
            Image(systemName: "crown.fill")
                .foregroundStyle(
                    isSubscribed
                        ? LinearGradient(colors: [.yellow, .orange], startPoint: .top, endPoint: .bottom)
                        : LinearGradient(colors: [.gray, .gray.opacity(0.7)], startPoint: .top, endPoint: .bottom)
                )
        }
    }
}

// Usage in toolbar:
ToolbarItem(placement: .primaryAction) {
    SubscriptionButton(
        presentingPassSheet: $presentingPassSheet,
        isSubscribed: InAppKit.shared.hasAnyPurchase
    )
}
.sheet(isPresented: $presentingPassSheet) {
    PaywallView()
}

Feature Gating with Item Limit

// Limit free users to 3 items
Button("Add Item") { }
    .requiresPurchase(whenItemCount: items.count, exceeds: 3)

Premium Feature Check

if InAppKit.shared.hasAnyPurchase {
    // Premium feature code
} else {
    // Free tier fallback
}

Custom Paywall Views

PaywallHeaderView:

struct PaywallHeaderView: View {
    var body: some View {
        VStack(spacing: 16) {
            Image("AppIcon")
                .resizable()
                .frame(width: 80, height: 80)
                .clipShape(RoundedRectangle(cornerRadius: 18))
            Text("App Pro")
                .font(.title.bold())
            Text("Unlock all features")
                .foregroundStyle(.secondary)
        }
    }
}

PaywallFeaturesView:

struct PaywallFeaturesView: View {
    var body: some View {
        VStack(alignment: .leading, spacing: 16) {
            FeatureRow(icon: "infinity", title: "Unlimited Items", description: "No limits")
            FeatureRow(icon: "sparkles", title: "Pro Features", description: "Exclusive access")
        }
        .padding()
    }
}

private struct FeatureRow: View {
    let icon: String
    let title: String
    let description: String

    var body: some View {
        HStack(alignment: .top, spacing: 12) {
            Image(systemName: icon)
                .font(.title2)
                .foregroundStyle(.mint)
                .frame(width: 32)
            VStack(alignment: .leading, spacing: 4) {
                Text(title).font(.headline)
                Text(description).font(.subheadline).foregroundStyle(.secondary)
            }
        }
    }
}

AppConstants Pattern

enum AppConstants {
    enum URLs {
        static let privacyPolicy = URL(string: "https://...")!
        static let termsOfUse = URL(string: "https://www.apple.com/legal/internet-services/itunes/dev/stdeula/")!
    }

    enum Products {
        static let monthly = "com.company.app.pass.monthly"
        static let yearly = "com.company.app.pass.yearly"
        static let lifetime = "com.company.app.pass.lifetime"
    }
}

Checklist

  • Add InAppKit dependency to Project.swift
  • Create StoreKit configuration file with products
  • Add .withPurchases() chain to app entry point
  • Create PaywallHeaderView and PaywallFeaturesView
  • Add AppConstants with product IDs and URLs
  • Add SubscriptionButton to main view toolbar
  • Gate premium features with .requiresPurchase()
  • Localize paywall feature strings
Install via CLI
npx skills add https://github.com/tddworks/InAppKit --skill inappkit-integration
Repository Details
star Stars 52
call_split Forks 6
navigation Branch main
article Path SKILL.md
More from Creator