iOS SDK

View as Markdown

The Unleash iOS SDK is a Swift client that lets you evaluate feature flags in iOS and macOS applications. It connects to Unleash or Unleash Edge to fetch evaluated flags for a given Unleash context.

You can use this SDK with Unleash Enterprise or Unleash Open Source.

For an overview of how Unleash SDKs work, including offline behavior, feature compatibility across SDKs, and default refresh and metrics intervals, refer to the SDK overview.

Requirements

  • MacOS: 12.15
  • iOS: 12

Usage

To get started, import the SDK and initialize the Unleash client:

iOS >= 13

1import SwiftUI
2import UnleashProxyClientSwift
3
4// Setup Unleash in the context where it makes most sense
5
6var unleash = UnleashProxyClientSwift.UnleashClient(
7 unleashUrl: "https://<unleash-instance>/api/frontend",
8 clientKey: "<client-side-api-token>",
9 refreshInterval: 15,
10 appName: "test",
11 context: ["userId": "c3b155b0-5ebe-4a20-8386-e0cab160051e"]
12)
13
14unleash.start()

iOS >= 12

1import SwiftUI
2import UnleashProxyClientSwift
3
4// Setup Unleash in the context where it makes most sense
5
6var unleash = UnleashProxyClientSwift.UnleashClientBase(
7 unleashUrl: "https://<unleash-instance>/api/frontend",
8 clientKey: "<client-side-api-token>",
9 refreshInterval: 15,
10 appName: "test",
11 context: ["userId": "c3b155b0-5ebe-4a20-8386-e0cab160051e"]
12)
13
14unleash.start()

In the example above we import the UnleashProxyClientSwift and instantiate the client. You need to provide the following parameters:

  • unleashUrl: The full URL to either the Unleash Frontend API or an Unleash Edge instance [String]
  • clientKey: A frontend API token for authenticating with the Frontend API or Unleash Edge [String]
  • refreshInterval: The polling interval in seconds, set to 0 to only poll once and disable a periodic polling [Int]
  • appName: The application name identifier [String]
  • context: Initial Unleash context fields (like userId, sessionId, etc.), excluding appName and environment which are configured separately. [String: String]

Calling unleash.start() makes the initial request to retrieve the feature flag configuration and starts the background polling interval (if refreshInterval > 0).

Until the client fetches the initial configuration (signaled by the ready event), checking a feature flag might return the default value (often false). To ensure the configuration is loaded before checking flags, subscribe to the ready event. See the Events section for details.

Once the configuration is loaded, you can check if a feature flag is enabled:

1if unleash.isEnabled(name: "ios") {
2 // do something
3} else {
4 // do something else
5}

You can also set up variants:

1var variant = unleash.getVariant(name: "ios")
2if variant.enabled {
3 // do something
4} else {
5 // do something else
6}

Configuration options

The Unleash SDK accepts the following initialization options:

optionrequireddefaultdescription
unleashUrlyesn/aThe Unleash Edge URL to connect to.
clientKeyyesn/aThe frontend token to use for authenticating with the Frontend API or Unleash Edge.
appNamenounleash-swift-clientThe name of the application using this SDK. Sent with metrics to Unleash Edge and included in the Unleash context.
environmentnodefaultThe name of the environment. Sent with metrics to Unleash Edge and included in the Unleash context.
refreshIntervalno15How often (in seconds) the SDK checks for updated flag configurations. Set to 0 to disable polling after initial fetch.
metricsIntervalno30How often (in seconds) the SDK sends usage metrics back to Unleash Edge.
disableMetricsnofalseSet this to true to disable usage metrics.
contextno[:]The initial context parameters excluding appName and environment which are specified as top level fields.
pollernonilA custom poller instance. If provided, the client ignores its own refreshInterval, customHeaders, customHeadersProvider, and bootstrap options. Use for advanced control or mocking.
pollerSessionnoURLSession.sharedSession object used for performing HTTP requests. You can provide a custom PollerSession for custom URLSession configuration or URLRequest interception.
customHeadersno[:]Additional headers to use when making HTTP requests to Unleash Edge. In case of name collisions with the default headers, the customHeaders value will be used.
customHeadersProvidernoDefaultCustomHeadersProviderCustom header provider for additional headers. In case of name collisions with the customHeaders, the customHeadersProvider value will be used.
bootstrapnoempty list of feature flagsInitial flag configurations provided to the Unleash client SDK. Can be a list of Toggle objects or the path to a JSON file matching the Frontend API response format. Available immediately on init, before the first fetch.

Bootstrap

You can bootstrap the SDK with flag configuration to evaluate flags before connecting to Unleash. Provide the bootstrap as a list of Toggle objects or from a JSON file matching the Frontend API response format.

1let bootstrapList = Bootstrap
2 .toggles(
3 [
4 Toggle(name: "Foo", enabled: true),
5 Toggle(
6 name: "Bar",
7 enabled: false,
8 variant: Variant(
9 name: "bar",
10 enabled: true,
11 featureEnabled: true,
12 payload: Payload(type: "string", value: "baz")
13 )
14 )
15 ]
16 )

You can inject the bootstrap at initialization or when calling start:

1import SwiftUI
2import UnleashProxyClientSwift
3
4let unleash = UnleashClient(
5 unleashUrl: "https://<unleash-instance>/api/frontend",
6 clientKey: "<client-side-api-token>",
7 bootstrap: .toggles([Toggle(name: "Foo", enabled: true)])
8)
9
10// Flags are available immediately
11let isFooEnabled = unleash.isEnabled(name: "Foo") // true
12
13// Or provide when starting
14unleash.start(bootstrap: .jsonFile("path/to/json/file"))
15
16// Or using async-await (iOS 13+)
17await unleash.start(bootstrap: .jsonFile("path/to/json/file"))
  • If you initialize the client with a Poller, inject the bootstrap directly into the poller. Any bootstrap data injected into the client options will be ignored when a custom poller is also provided.
  • Bootstrapped flag configurations are replaced entirely after the first successful fetch.
  • If bootstrap flags are provided when calling start, the first fetch occurs after the configured refreshInterval (default 15 seconds).
  • Calling updateContext(...) before the first fetch removes any bootstrapped flags.

Update context

To update the context, use the following method:

1var context: [String: String] = [:]
2context["userId"] = "c3b155b0-5ebe-4a20-8386-e0cab160051e"
3unleash.updateContext(context: context)

This will stop and start the polling interval in order to renew polling with new context values.

You can use any of the predefined fields. If you need to support custom properties pass them as the second argument:

1var context: [String: String] = [:]
2context["userId"] = "c3b155b0-5ebe-4a20-8386-e0cab160051e"
3var properties: [String: String] = [:]
4properties["customKey"] = "customValue";
5unleash.updateContext(context: context, properties: properties)

Custom PollerSession

If you want to use a custom URLSession or intercept URLRequest you can provide a custom PollerSession to the client.

1class CustomPollerSession: PollerSession {
2 func perform(_ request: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) {
3 // Custom URLSession configuration
4 let configuration = URLSessionConfiguration.default
5 configuration.timeoutIntervalForRequest = 30
6
7 // Modify URLRequest if needed
8 var modifiedRequest = request
9 modifiedRequest.setValue("foo", forHTTPHeaderField: "bar")
10
11 let session = URLSession(configuration: configuration)
12 session.dataTask(with: modifiedRequest, completionHandler: completionHandler).resume()
13 }
14}
15
16// Use when initializing Unleash client
17var unleash = UnleashProxyClientSwift.UnleashClient(
18 unleashUrl: unleashUrl,
19 clientKey: clientKey,
20 pollerSession: CustomPollerSession()
21)

Custom HTTP headers

If you want the client to send custom HTTP headers with all requests to the Unleash API you can define that by setting them via the UnleashClientBase.

Custom and dynamic custom headers does not apply to sensitive headers.

  • Content-Type
  • If-None-Match
  • anything starting with unleash- (unleash-appname, unleash-connection-id, unleash-sdk, …)
1var unleash = UnleashProxyClientSwift.UnleashClientBase(
2 unleashUrl: unleashUrl,
3 clientKey: clientKey,
4 refreshInterval: 15,
5 appName: "test",
6 context: ["userId": "c3b155b0-5ebe-4a20-8386-e0cab160051e"],
7 customHeaders: ["X-Custom-Header": "CustomValue", "X-Another-Header": "AnotherValue"]
8)

Dynamic custom HTTP headers

If you need custom HTTP headers that change during the lifetime of the client, a provider can be defined via the UnleashClientBase.

1public class MyCustomHeadersProvider: CustomHeadersProvider {
2 public init() {}
3 public func getCustomHeaders() -> [String: String] {
4 let token = "Acquire or refresh token";
5 return ["Authorization": token]
6 }
7}
1let myCustomHeadersProvider: CustomHeadersProvider = MyCustomHeadersProvider()
2
3var unleash = UnleashProxyClientSwift.UnleashClientBase(
4 unleashUrl: unleashUrl,
5 clientKey: clientKey,
6 refreshInterval: 15,
7 appName: "test",
8 context: ["userId": "c3b155b0-5ebe-4a20-8386-e0cab160051e"],
9 customHeadersProvider: myCustomHeadersProvider
10)

Events

The client emits events that you can subscribe to using the subscribe(name:callback:) method or the UnleashEvent enum.

The client emits the following events:

  • ready (UnleashEvent.ready): Emitted once the client has successfully fetched and cached the initial feature flag configurations.
  • update (UnleashEvent.update): Emitted when a subsequent fetch results in a change to the feature flag configurations.
  • sent (UnleashEvent.sent): Emitted when usage metrics have been successfully sent to the server.
  • error (UnleashEvent.error): Emitted if an error occurs when trying to send metrics.
  • impression (UnleashEvent.impression): Emitted when isEnabled(name:) or getVariant(name:) is called for a flag with impression data enabled.

Subscribe using the subscribe(name:callback:) method or the UnleashEvent enum:

1func handleReady() {
2 // do this when unleash is ready
3}
4
5unleash.subscribe(name: "ready", callback: handleReady)
6
7// Or using the enum:
8unleash.subscribe(.ready, callback: handleReady)

Impression events

To track feature exposures, enable impression data for the flags you want to track, then subscribe to the impression event:

1import UnleashProxyClientSwift
2
3func handleImpressionEvent(_ payload: Any?) {
4 guard let impressionEvent = payload as? UnleashProxyClientSwift.ImpressionEvent else {
5 return
6 }
7
8 // Send impression data to your analytics tool
9}
10
11unleash.subscribe(.impression, callback: handleImpressionEvent)

Installation

In your Xcode project, go to File -> Swift Packages -> Add Package Dependency, supply the link to this repository, and set the appropriate package constraints (typically up to next major version).

Migrating to v2

In v2, the StorageProvider interface was changed to accept all flags at once:

1func set(values: [String: Toggle])

If you have a custom StorageProvider implementation, you’ll need to update it.