iOS SDK
Segment membership
This package only evaluates published targeting lists. It has no membership write API and must not hold a Backend application key.
Update members from your backend. Call membership from your backend SDK, not from the iOS app. Flow.
Frontend telemetry
Use iOS SDK 1.5.2 or later for compact frontend telemetry across Core, SwiftUI, UIKit, and
Combine. Configure it on TogglyConfig; explicit events are async and available
on an owned TogglyService or Toggly.shared.
import TogglyCore
// Run from an async application task; retain this owner for its full lifetime.
let service = TogglyService(config: TogglyConfig(
appKey: "YOUR_APP_KEY",
environment: "Production",
enableTelemetry: true,
metricsBaseUrl: "https://metrics.toggly.io",
telemetryFlushIntervalMs: 45_000
))
await service.initialize()
await service.recordUsage("new-checkout")
await service.recordView("new-checkout", variant: "blue")
await service.incrementCounter("orders", value: 2)
await service.setGauge("cart_total", value: 12.5)
await service.flushTelemetry()
await service.setAppState(.background)
await service.dispose() // only when this owner ends
SwiftUI, UIKit, and Combine count the feature values they actually evaluate or present. Forward application backgrounding and dispose directly owned services; the SDK bounds both operations. See the frontend telemetry contract.
Use Toggly's native iOS SDK in Swift applications for iOS, macOS, tvOS, and watchOS.
Grab the printable Swift / iOS cheat sheet (download PDF) — SwiftUI property wrappers, UIKit, Combine, signed defs.
Session identity
Set instanceId in TogglyConfig. On the same service, call
await service.setIdentity("user-123", instanceId: "minted-token") or
await service.setInstanceId("minted-token"). setInstanceId(nil) clears the
token; setIdentity(nil) also clears it and returns to the device identity.
Core and Toggly.shared expose these async APIs; UI and Combine integrations
must reuse their existing service rather than constructing another reporter.
See session attribution.
Overview
The iOS SDK is a modular feature flags solution built entirely in Swift with async/await support. It provides SwiftUI property wrappers, UIKit extensions, and Combine publishers for seamless integration.
Packages
| Package | Description |
|---|---|
TogglyCore | Core functionality, storage, and API client (required) |
TogglySwiftUI | SwiftUI property wrappers, view modifiers, and views |
TogglyUIKit | UIKit extensions and view controller support |
TogglyCombine | Combine publishers for reactive patterns |
Requirements
- iOS 14.0+ / macOS 11.0+ / tvOS 14.0+ / watchOS 7.0+
- Swift 5.5+
- Xcode 15.0+
Installation
Use the published ios-sdk-v1.5.2 tag or later. This tag includes the root
Swift Package Manager manifest; earlier tags without that manifest cannot be
installed directly from the repository URL.
Swift Package Manager
Use the prefixed release tag as a Git revision. Add the package to your Package.swift:
dependencies: [
.package(url: "https://github.com/ops-ai/Toggly.FeatureManagement.git", revision: "ios-sdk-v1.5.2")
]
Then add the products you need:
.target(
name: "YourApp",
dependencies: [
.product(name: "TogglyCore", package: "Toggly.FeatureManagement"),
.product(name: "TogglySwiftUI", package: "Toggly.FeatureManagement"),
.product(name: "TogglyUIKit", package: "Toggly.FeatureManagement"),
.product(name: "TogglyCombine", package: "Toggly.FeatureManagement"),
]
)
Xcode
- File → Add Package Dependencies
- Enter:
https://github.com/ops-ai/Toggly.FeatureManagement.git - Open the published
ios-sdk-v1.5.2tag and copy the full commit SHA it points to. - Choose the Commit dependency rule and enter that full commit SHA.
- Select the products you need (
TogglyCoreis always required).
Quick Start
Initialize the SDK
import TogglyCore
@main
struct MyApp: App {
init() {
// Configure with your Toggly app key
Toggly.configure(config: TogglyConfig(
appKey: "your-app-key",
environment: "Production"
))
// Initialize asynchronously
Task {
await Toggly.shared.initialize()
}
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
SwiftUI Usage
import TogglySwiftUI
struct ContentView: View {
// Use the @FeatureFlag property wrapper
@FeatureFlag("new-dashboard") var isNewDashboardEnabled
var body: some View {
VStack {
if isNewDashboardEnabled {
NewDashboardView()
} else {
LegacyDashboardView()
}
// Or use the view modifier
Text("Beta Feature")
.featureFlag("beta-feature")
// Or use FeatureView for cleaner conditional rendering
FeatureView("welcome-banner") {
WelcomeBanner()
}
}
}
}
UIKit Usage
import TogglyUIKit
class MyViewController: FeatureFlagViewController {
override func viewDidLoad() {
super.viewDidLoad()
observeFeature("new-dashboard")
}
override func featureFlagDidChange(_ key: String, isEnabled: Bool) {
// Update UI based on feature flag changes
newDashboardView.isHidden = !isEnabled
}
}
Combine Usage
import TogglyCombine
class ViewModel: ObservableObject {
@Published var isFeatureEnabled = false
private var cancellables = Set<AnyCancellable>()
init() {
TogglyPublishers.featureFlag("new-dashboard")
.receive(on: DispatchQueue.main)
.assign(to: &$isFeatureEnabled)
}
}
Async/Await Usage
import TogglyCore
// Simple feature check
let isEnabled = await Toggly.shared.isFeatureOn("my-feature")
// Feature gate with multiple features
let allEnabled = await Toggly.shared.evaluateFeatureGate(
featureKeys: ["feature-a", "feature-b"],
requirement: .all
)
Variants
Set enableVariants: true on TogglyConfig to fetch server-evaluated
variant assignments alongside plain booleans. isFeatureOn and
evaluateFeatureGate keep working exactly as before — they depend on
enabled alone, regardless of any variant assignment. getVariant and
getVariantValue are stricter: they return a value only when the feature is
enabled and the server has assigned it a variant; either check on its
own returns nil.
Toggly.configure(config: TogglyConfig(
appKey: "your-app-key",
enableVariants: true
))
await Toggly.shared.initialize()
if let variant = await Toggly.shared.getVariant("checkout-experiment") {
switch variant.name {
case "Treatment": showTreatment(config: variant.configurationValue)
default: showControl()
}
}
// Or fetch only the payload:
let config = await Toggly.shared.getVariantValue("checkout-experiment")
getVariant returns nil when the feature is off or has no variant
assigned. configurationValue is an untyped JSON payload (Any?) — cast it
to the shape your dashboard configuration uses. In SwiftUI, use the
@FeatureVariant property wrapper from TogglySwiftUI for reactive access.
Configuration Options
TogglyConfig(
appKey: "your-app-key", // Your Toggly.io app key
environment: "Production", // Environment name
baseURI: "https://definitions.toggly.io", // API endpoint (optional)
identity: "user-123", // User ID for targeting (optional)
featureDefaults: [ // Default values (optional)
"feature-a": true,
"feature-b": false
],
showFeatureDuringEvaluation: false, // Show content while loading
refreshInterval: 180, // Auto-refresh interval (seconds)
useSignedDefinitions: false, // Use signed definitions
storage: UserDefaultsStorage() // Custom storage (optional)
)
Offline Support
The SDK automatically caches feature flags for offline use:
// Use UserDefaults for persistent storage
let config = TogglyConfig(
appKey: "your-app-key",
environment: "Production",
storage: UserDefaultsStorage()
)
Local-Only Mode
Use the SDK without connecting to Toggly.io:
let config = TogglyConfig(
featureDefaults: [
"new-dashboard": true,
"beta-feature": false
]
)
Toggly.configure(config: config)
await Toggly.shared.initialize()
Entity context
Pass the screen entity on each evaluation — not via setIdentity. See Entity & page context.
iOS is a client: local registerContext only. No PUT sdk/{appKey}/contexts.
Toggly.shared.registerContext("Order") { value in
let order = value as! Order // This mapper is called with your Order model.
return TogglyEntityContext(
kind: "Order", key: String(order.id),
attributes: ["Status": order.status]
)
}
let on = await Toggly.shared.isEnabled("OrderBadge", context: order, kind: "Order")
Gates fail closed without context. Identity is user only.
Next Steps
- Learn about SwiftUI Integration with property wrappers and view modifiers
- Explore UIKit Support for view controllers and extensions
- See Combine Publishers for reactive patterns
- Read about Configuration options
- Check Advanced Usage for identity management and events