Skip to main content

Installation

Swift Package Manager

In Xcode: File → Add Packages, then enter:
https://github.com/gatlio/gatlio-swift
Or in Package.swift:
.package(url: "https://github.com/gatlio/gatlio-swift.git", from: "1.0.0")
Add GatlioUI as a target dependency (and optionally Gatlio for direct client usage):
.target(
    name: "YourApp",
    dependencies: [
        .product(name: "GatlioUI", package: "gatlio-swift"),
    ]
)

Quick start

Wrap the authenticated portion of your app in GatlioGate:
import GatlioUI

GatlioGate(
    tenantSlug: "acme",
    customerId: currentUser.stripeCustomerId,
    publishableKey: "pk_live_abc123",
    apiBase: "https://api.gatlio.io"
) {
    YourApp()
}
  • ActiveYourApp renders normally
  • Warning — dismissable banner above content
  • Lockout — full-screen overlay until card is updated

Parameters

ParameterTypeRequiredDefault
tenantSlugString
customerIdString
publishableKeyString
apiBaseString
pollIntervalTimeInterval600
forcedStatusGatlioStatus?nil
callbacksGatlioCallbacks?nil
lockoutScreen((@escaping () -> Void, Entitlements?) -> AnyView)?built-in
warningBanner((@escaping () -> Void, @escaping () -> Void) -> AnyView)?built-in
content@ViewBuilder

Callbacks

GatlioGate(
    tenantSlug: "acme",
    customerId: currentUser.stripeCustomerId,
    publishableKey: "pk_live_abc123",
    apiBase: "https://api.gatlio.io",
    callbacks: GatlioCallbacks(
        onLockout: { print("locked out") },
        onWarning: { print("warning") },
        onActive: { print("active") },
        onRecovered: { print("recovered") },
        onError: { err in print("error: \(err)") }
    )
) {
    YourApp()
}
Callbacks fire on status transitions only.

Custom enforcement UI

Wrap your views in AnyView(...):
GatlioGate(
    // ...
    lockoutScreen: { triggerCardUpdate, _ in
        AnyView(MyBrandedLockout(onUpdate: triggerCardUpdate))
    },
    warningBanner: { triggerCardUpdate, dismissWarning in
        AnyView(MyBrandedBanner(onUpdate: triggerCardUpdate, onDismiss: dismissWarning))
    }
) {
    YourApp()
}

Testing

Force a state

GatlioGate(
    tenantSlug: "acme",
    customerId: "cus_test",
    publishableKey: "pk_test_abc",
    apiBase: "https://api.gatlio.io",
    forcedStatus: .lockout
) {
    YourApp()
}
No network calls are made when forcedStatus is set. Remove before shipping.

Interactive sandbox

import GatlioUI

GatlioSandbox(
    onLockout: { print("locked out") },
    onWarning: { print("warning") },
    onActive: { print("active") },
    onError: { err in print("error: \(err)") }
) {
    YourApp()
}
A DEV badge appears in the bottom-right corner. Tap to open a sheet with state pills and a callback log. Remove before shipping to production.

UIKit / non-SwiftUI usage

Use the Gatlio target directly with Combine:
import Gatlio

let client = GatlioClient(
    config: GatlioConfig(
        apiBase: "https://api.gatlio.io",
        tenantSlug: "acme",
        customerId: currentUser.stripeCustomerId,
        publishableKey: "pk_live_abc123"
    )
)
client.start()

client.$status
    .receive(on: DispatchQueue.main)
    .sink { status in /* update UI */ }
    .store(in: &cancellables)
Call client.stop() in deinit or viewDidDisappear.