Quickstart by stack

iOS Quickstart

Install the Swift SDK with Swift Package Manager, read a flag from SwiftUI, and target users with context.

Prerequisites

  • iOS 13 or later, Xcode 15 or later, and Swift 5.9 or later.
  • A mobile key (prefixed mob_) or a client key (prefixed cli_) from your environment. Server keys (srv_) are rejected when you create the SDK, because anything bundled in an app can be extracted.
  • A flag key you can test in a non-production environment.
Install with Package.swift swift

dependencies: [
    .package(url: "https://github.com/zenmanage/zenmanage-swift.git", from: "1.0.0")
],
targets: [
    .target(
        name: "YourApp",
        dependencies: [
            .product(name: "Zenmanage", package: "zenmanage-swift")
        ]
    )
]

In Xcode, choose File → Add Package Dependencies, paste https://github.com/zenmanage/zenmanage-swift.git, and add the Zenmanage library to your app target.

Initialize and evaluate swift

import Zenmanage

let zenmanage = try Zenmanage(environmentToken: "mob_your_mobile_key_here")

let flag = try await zenmanage.flags().single("new-dashboard", defaultValue: false)

if flag.isEnabled() {
    showNewDashboard()
} else {
    showOldDashboard()
}

Safe defaults

The default you pass to single is what you get when the flag doesn't exist or the rules can't be loaded, such as an offline device with nothing cached or a wrong key. Rules are fetched once and evaluated on the device, so reading a flag never waits on a per-flag network call.

One instance per app

Create a single Zenmanage at launch and pass it down. It keeps the loaded rules in memory, so build it once instead of per screen.

Read a flag from SwiftUI swift

import SwiftUI
import Zenmanage

struct DashboardView: View {
    let zenmanage: Zenmanage
    @State private var showNewDashboard = false

    var body: some View {
        Group {
            if showNewDashboard {
                NewDashboardView()
            } else {
                LegacyDashboardView()
            }
        }
        .task {
            let flag = try? await zenmanage.flags().single("new-dashboard", defaultValue: false)
            showNewDashboard = flag?.isEnabled() ?? false
        }
    }
}
Target a user with context swift

let context = Context(
    type: "user",
    name: "Taylor",
    identifier: "user-123",
    attributes: [
        Attribute("country", values: ["US"]),
        Attribute("plan", values: ["pro"]),
    ]
)

let flag = try await zenmanage.flags()
    .withContext(context)
    .single("premium-dashboard", defaultValue: false)
Run an A/B test with a string flag swift

let variant = try await zenmanage.flags()
    .withContext(context)
    .single("checkout-flow", defaultValue: "control")

switch variant.asString() {
case "one-page":
    showOnePageCheckout()
default:
    showMultiPageCheckout()
}
Read a JSON value swift

let config = try await zenmanage.flags()
    .single("advanced-config", defaultValue: ["retries": 3, "timeout-ms": 5000])
    .asJson()

Stable percentage rollouts

The SDK hashes the rollout salt and your context identifier into a bucket from 0 to 99, so a user stays in or out of a rollout across launches. Raising the percentage only adds users. Pass a stable identifier, such as your user ID, in the context.

Cached in UserDefaults

Rules are cached in UserDefaults for an hour by default, so a cold launch evaluates flags from the cache without a network call until it expires. Pass cacheTTL to change the lifetime, or swap in InMemoryRuleCache() or NullRuleCache() through the cache parameter.

Mobile or client keys only

Use a mob_ or cli_ key in the app. A srv_ key throws when you create the SDK. Keys in an app bundle are readable by anyone with the binary, so keep server keys on your backend.

Swift Package Manager only

The SDK ships through Swift Package Manager. There is no CocoaPods podspec. A bridge for Objective-C is included, so mixed-language apps can import the same package.

Next step

Take the next integration step in your own stack.

Start with the quickstart that matches your runtime, then return to the reference pages when you need exact request and payload details.

Language and framework names and logos shown above are trademarks or registered trademarks of their respective owners. Their use here is for identification purposes only and does not imply endorsement of, or affiliation with, Zenmanage.