https://github.com/open-feature/swift-sdk
Swift implementation of the OpenFeature SDK for iOS clients
https://github.com/open-feature/swift-sdk
sdk
Last synced: about 1 year ago
JSON representation
Swift implementation of the OpenFeature SDK for iOS clients
- Host: GitHub
- URL: https://github.com/open-feature/swift-sdk
- Owner: open-feature
- License: apache-2.0
- Created: 2023-07-07T20:31:30.000Z (about 3 years ago)
- Default Branch: main
- Last Pushed: 2025-03-29T03:07:00.000Z (over 1 year ago)
- Last Synced: 2025-04-15T04:01:42.108Z (about 1 year ago)
- Topics: sdk
- Language: Swift
- Homepage: https://openfeature.dev
- Size: 99.6 KB
- Stars: 19
- Watchers: 8
- Forks: 3
- Open Issues: 9
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
OpenFeature iOS SDK
[OpenFeature](https://openfeature.dev) is an open specification that provides a vendor-agnostic, community-driven API for feature flagging that works with your favorite feature flag management tool or in-house solution.
## 🚀 Quick start
### Requirements
- The minimum iOS version supported is: `iOS 14`.
Note that this library is intended to be used in a mobile context, and has not been evaluated for use in other type of applications (e.g. server applications, macOS, tvOS, watchOS, etc.).
### Install
#### Xcode Dependencies
You have two options, both start from File > Add Packages... in the code menu.
First, ensure you have your GitHub account added as an option (+ > Add Source Control Account...). You will need to create a [Personal Access Token](https://github.com/settings/tokens) with the permissions defined in the Xcode interface.
1. Add as a remote repository
* Search for `git@github.com:open-feature/swift-sdk.git` and click "Add Package"
2. Clone the repository locally
* Clone locally using your preferred method
* Use the "Add Local..." button to select the local folder
**Note:** Option 2 is only recommended if you are making changes to the client SDK.
#### Swift Package Manager
If you manage dependencies through SPM, in the dependencies section of Package.swift add:
```swift
.package(url: "git@github.com:open-feature/swift-sdk.git", from: "0.3.0")
```
and in the target dependencies section add:
```swift
.product(name: "OpenFeature", package: "swift-sdk"),
```
### Usage
```swift
import OpenFeature
Task {
let provider = CustomProvider()
// configure a provider, wait for it to complete its initialization tasks
await OpenFeatureAPI.shared.setProviderAndWait(provider: provider)
// get a bool flag value
let client = OpenFeatureAPI.shared.getClient()
let flagValue = client.getBooleanValue(key: "boolFlag", defaultValue: false)
}
```
## 🌟 Features
| Status | Features | Description |
| ------ | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| ✅ | [Providers](#providers) | Integrate with a commercial, open source, or in-house feature management tool. |
| ✅ | [Targeting](#targeting) | Contextually-aware flag evaluation using [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context). |
| ✅ | [Hooks](#hooks) | Add functionality to various stages of the flag evaluation life-cycle. |
| ❌ | [Tracking](#tracking) | Associate user actions with feature flag evaluations. |
| ❌ | [Logging](#logging) | Integrate with popular logging packages. |
| ❌ | [Named clients](#named-clients) | Utilize multiple providers in a single application. |
| ✅ | [Eventing](#eventing) | React to state changes in the provider or flag management system. |
| ❌ | [Shutdown](#shutdown) | Gracefully clean up a provider during application shutdown. |
| ✅ | [Extending](#extending) | Extend OpenFeature with custom providers and hooks. |
Implemented: ✅ | In-progress: ⚠️ | Not implemented yet: ❌
### Providers
[Providers](https://openfeature.dev/docs/reference/concepts/provider) are an abstraction between a flag management system and the OpenFeature SDK.
Look [here](https://openfeature.dev/ecosystem?instant_search%5BrefinementList%5D%5Btype%5D%5B0%5D=Provider&instant_search%5BrefinementList%5D%5Btechnology%5D%5B0%5D=Swift) for a complete list of available providers.
If the provider you're looking for hasn't been created yet, see the [develop a provider](#develop-a-provider) section to learn how to build it yourself.
Once you've added a provider as a dependency, it can be registered with OpenFeature like this:
```swift
await OpenFeatureAPI.shared.setProviderAndWait(provider: MyProvider())
```
> Asynchronous API that doesn't wait is also available
### Targeting
Sometimes, the value of a flag must consider some dynamic criteria about the application or user, such as the user's location, IP, email address, or the server's location.
In OpenFeature, we refer to this as [targeting](https://openfeature.dev/specification/glossary#targeting).
If the flag management system you're using supports targeting, you can provide the input data using the [evaluation context](https://openfeature.dev/docs/reference/concepts/evaluation-context).
```swift
// Configure your evaluation context and pass it to OpenFeatureAPI
let ctx = MutableContext(
targetingKey: userId,
structure: MutableStructure(attributes: ["product": Value.string(productId)]))
OpenFeatureAPI.shared.setEvaluationContext(evaluationContext: ctx)
```
### Hooks
[Hooks](https://openfeature.dev/docs/reference/concepts/hooks) allow for custom logic to be added at well-defined points of the flag evaluation life-cycle.
Look [here](https://openfeature.dev/ecosystem/?instant_search%5BrefinementList%5D%5Btype%5D%5B0%5D=Hook&instant_search%5BrefinementList%5D%5Btechnology%5D%5B0%5D=Swift) for a complete list of available hooks.
If the hook you're looking for hasn't been created yet, see the [develop a hook](#develop-a-hook) section to learn how to build it yourself.
Once you've added a hook as a dependency, it can be registered at the global, client, or flag invocation level.
```swift
// add a hook globally, to run on all evaluations
OpenFeatureAPI.shared.addHooks(hooks: ExampleHook())
// add a hook on this client, to run on all evaluations made by this client
val client = OpenFeatureAPI.shared.getClient()
client.addHooks(ExampleHook())
// add a hook for this evaluation only
_ = client.getValue(
key: "key",
defaultValue: false,
options: FlagEvaluationOptions(hooks: [ExampleHook()]))
```
### Tracking
Tracking is not yet available in the iOS SDK.
### Logging
Logging customization is not yet available in the iOS SDK.
### Named clients
Support for named clients is not yet available in the iOS SDK.
### Eventing
Events allow you to react to state changes in the provider or underlying flag management system, such as flag definition changes, provider readiness, or error conditions.
Initialization events (`PROVIDER_READY` on success, `PROVIDER_ERROR` on failure) are dispatched for every provider.
Some providers support additional events, such as `PROVIDER_CONFIGURATION_CHANGED`.
Please refer to the documentation of the provider you're using to see what events are supported.
```swift
let cancellable = OpenFeatureAPI.shared.observe().sink { event in
switch event {
case ProviderEvent.ready:
// ...
default:
// ...
}
}
```
### Shutdown
A shutdown function is not yet available in the iOS SDK.
## Extending
### Develop a provider
To develop a provider, you need to create a new project and include the OpenFeature SDK as a dependency.
You’ll then need to write the provider by implementing the `FeatureProvider` interface exported by the OpenFeature SDK.
```swift
import OpenFeature
final class CustomProvider: FeatureProvider {
var hooks: [any Hook] = []
var metadata: ProviderMetadata = CustomMetadata()
func initialize(initialContext: EvaluationContext?) async {
// add context-aware provider initialisation
}
func onContextSet(oldContext: EvaluationContext?, newContext: EvaluationContext) async {
// add necessary changes on context change
}
func getBooleanEvaluation(
key: String,
defaultValue: Bool,
context: EvaluationContext?
) throws -> ProviderEvaluation {
// resolve a boolean flag value
}
...
}
```
> Built a new provider? [Let us know](https://github.com/open-feature/openfeature.dev/issues/new?assignees=&labels=provider&projects=&template=document-provider.yaml&title=%5BProvider%5D%3A+) so we can add it to the docs!
### Develop a hook
To develop a hook, you need to create a new project and include the OpenFeature SDK as a dependency.
Implement your own hook by conforming to the `Hook interface`.
To satisfy the interface, all methods (`Before`/`After`/`Finally`/`Error`) need to be defined.
```swift
class BooleanHook: Hook {
typealias HookValue = Bool
func before(ctx: HookContext, hints: [String: Any]) {
// do something
}
func after(ctx: HookContext, details: FlagEvaluationDetails, hints: [String: Any]) {
// do something
}
func error(ctx: HookContext, error: Error, hints: [String: Any]) {
// do something
}
func finally(ctx: HookContext, hints: [String: Any]) {
// do something
}
}
```
> Built a new hook? [Let us know](https://github.com/open-feature/openfeature.dev/issues/new?assignees=&labels=hook&projects=&template=document-hook.yaml&title=%5BHook%5D%3A+) so we can add it to the docs!
## ⭐️ Support the project
- Give this repo a ⭐️!
- Follow us on social media:
- Twitter: [@openfeature](https://twitter.com/openfeature)
- LinkedIn: [OpenFeature](https://www.linkedin.com/company/openfeature/)
- Join us on [Slack](https://cloud-native.slack.com/archives/C0344AANLA1)
- For more, check out our [community page](https://openfeature.dev/community/)
## 🤝 Contributing
Interested in contributing? Great, we'd love your help! To get started, take a look at the [CONTRIBUTING](CONTRIBUTING.md) guide.
### Thanks to everyone who has already contributed
Made with [contrib.rocks](https://contrib.rocks).