-
Notifications
You must be signed in to change notification settings - Fork 122
chore: update sdk readmes #1539
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,7 +10,7 @@ This content has been automatically generated from swift-sdk. | |
| Edits should be made here: https://github.com/open-feature/swift-sdk | ||
| Once a repo has been updated, docs can be generated by running: yarn update:sdk-docs | ||
|
|
||
| Last updated at Mon Sep 21 2026 08:42:23 GMT+0000 (Coordinated Universal Time) | ||
| Last updated at Thu Oct 01 2026 08:28:06 GMT+0000 (Coordinated Universal Time) | ||
| --> | ||
| import MCPInstall from '@site/src/partials/mcp-install'; | ||
|
|
||
|
|
@@ -44,7 +44,7 @@ This SDK supports the following Apple platforms: | |
| - **watchOS 8+** | ||
| - **tvOS 15+** | ||
|
|
||
| The SDK is built with Swift 5.5+ and uses Foundation, Combine, and the [swift-log](https://github.com/apple/swift-log) Logging package, making it suitable for all Apple platform contexts including mobile, desktop, wearable, and TV applications. | ||
| The SDK is built with Swift 5.5+ and uses only Foundation and Combine, making it suitable for all Apple platform contexts including mobile, desktop, wearable, and TV applications. It has no third-party dependencies. An optional `OpenFeatureSwiftLog` product integrates with [swift-log](https://github.com/apple/swift-log) for those who use it (see [Logging](#logging)). | ||
|
|
||
| ### Install | ||
|
|
||
|
|
@@ -75,18 +75,9 @@ and in the target dependencies section add: | |
| .product(name: "OpenFeature", package: "swift-sdk"), | ||
| ``` | ||
|
|
||
| #### CocoaPods | ||
|
|
||
| If you manage dependencies through CocoaPods, add the following to your Podfile: | ||
|
|
||
| ```ruby | ||
| pod 'OpenFeature', '~> 0.5.0' | ||
| ``` | ||
|
|
||
| Then, run: | ||
|
|
||
| ```bash | ||
| pod install | ||
| To log through [swift-log](https://github.com/apple/swift-log), also add the optional bridge product: | ||
| ```swift | ||
| .product(name: "OpenFeatureSwiftLog", package: "swift-sdk"), | ||
| ``` | ||
|
|
||
| ### iOS Usage | ||
|
|
@@ -105,6 +96,18 @@ Task { | |
| } | ||
| ``` | ||
|
|
||
| ### Privacy Manifest | ||
|
|
||
| The SDK ships a [privacy manifest](https://developer.apple.com/documentation/bundleresources/privacy-manifest-files) (`PrivacyInfo.xcprivacy`) that Swift Package Manager bundles automatically, so it is picked up by Xcode's privacy report and App Store submission checks. | ||
|
|
||
| The manifest declares that the SDK: | ||
|
|
||
| * does not track users (`NSPrivacyTracking` is `false`) and contacts no tracking domains, | ||
| * does not collect any data types on its own, | ||
| * does not call any [required reason APIs](https://developer.apple.com/documentation/bundleresources/describing-use-of-required-reason-api). | ||
|
|
||
| The SDK is an abstraction layer, it holds the evaluation context and tracking events your app supplies and hands them to the configured provider, but never persists or transmits them itself. Any data collection, tracking or required-reason API usage happens in the provider (or hook) you install. Third-party providers and hooks are responsible for declaring that in their own privacy manifest, so check the manifest of each one you use. Your app's own manifest must cover data collection, tracking, and required-reason API use by your app's code, including any custom providers or hooks you write yourself. | ||
|
|
||
| ## Features | ||
|
|
||
| | Status | Features | Description | | ||
|
|
@@ -113,9 +116,10 @@ Task { | |
| | ✅ | [Targeting](#targeting) | Contextually-aware flag evaluation using [evaluation context](/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. | | ||
| | ✅ | [Logging](#logging) | Integrate with popular logging packages or your own logger. | | ||
| | ❌ | [Domains](#domains) | Logically bind clients with providers. | | ||
| | ✅ | [MultiProvider](#multiprovider) | Combine multiple providers with configurable evaluation strategies. | | ||
| | ✅ | [InMemoryProvider](#inmemoryprovider) | Resolve flags from an in-memory configuration, for demos and testing. | | ||
| | ✅ | [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. | | ||
|
|
@@ -194,40 +198,97 @@ Note that some providers may not support tracking; check the documentation for y | |
|
|
||
| ### Logging | ||
|
|
||
| The iOS SDK integrates with [swift-log](https://github.com/apple/swift-log), the standard logging API for Swift. This provides a unified, cross-platform logging interface that works with any swift-log compatible backend. | ||
| The SDK does not depend on any logging framework. It logs through the small `OpenFeatureLogger` protocol, so you can plug in whatever logger your app already uses: | ||
|
|
||
| #### Configure Logger | ||
| ```swift | ||
| public protocol OpenFeatureLogger { | ||
| func debug(_ message: @autoclosure () -> String) | ||
| func info(_ message: @autoclosure () -> String) | ||
| func warning(_ message: @autoclosure () -> String) | ||
| func error(_ message: @autoclosure () -> String) | ||
| } | ||
| ``` | ||
|
|
||
| You can configure logging at three levels, with each level taking precedence over the previous: | ||
| Messages are autoclosures, so string interpolation only runs if your implementation emits the message. Implementations may be called from any thread and must be thread-safe. | ||
|
|
||
| #### Bring your own logger | ||
|
|
||
| Conform your logger to `OpenFeatureLogger`. For example, with Apple's unified logging: | ||
|
|
||
| ```swift | ||
| import OpenFeature | ||
| import os | ||
|
|
||
| struct OSLogOpenFeatureLogger: OpenFeatureLogger { | ||
| private let logger = os.Logger(subsystem: "com.example.app", category: "openfeature") | ||
|
|
||
| func debug(_ message: @autoclosure () -> String) { logger.debug("\(message())") } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Account for unified logging's string privacy default. Each method in this example interpolates 🤖 Prompt for AI Agents |
||
| func info(_ message: @autoclosure () -> String) { logger.info("\(message())") } | ||
| func warning(_ message: @autoclosure () -> String) { logger.warning("\(message())") } | ||
| func error(_ message: @autoclosure () -> String) { logger.error("\(message())") } | ||
| } | ||
| ``` | ||
|
|
||
| #### Using swift-log | ||
|
|
||
| If you use [swift-log](https://github.com/apple/swift-log), the optional `OpenFeatureSwiftLog` product ships a ready-made `SwiftLogLogger` that forwards to a swift-log `Logger`: | ||
|
|
||
| **1. Global (API-level)** - affects all flag evaluations: | ||
| ```swift | ||
| import Logging | ||
| import OpenFeature | ||
| import OpenFeatureSwiftLog | ||
|
|
||
| let logger = Logger(label: "com.example.app.openfeature") | ||
| let logger = SwiftLogLogger(Logger(label: "com.example.app.openfeature")) | ||
| // or simply: SwiftLogLogger(label: "com.example.app.openfeature") | ||
| OpenFeatureAPI.shared.setLogger(logger) | ||
| ``` | ||
|
|
||
| The core `OpenFeature` product never links swift-log; only apps that add `OpenFeatureSwiftLog` do. | ||
|
|
||
| #### Configure Logger | ||
|
|
||
| You can configure logging at three levels, with each level taking precedence over the previous: | ||
|
|
||
| **1. Global (API-level)** - affects all flag evaluations: | ||
| ```swift | ||
| OpenFeatureAPI.shared.setLogger(OSLogOpenFeatureLogger()) | ||
| ``` | ||
|
|
||
| **2. Client-level** - affects all evaluations from a specific client: | ||
| ```swift | ||
| let client = OpenFeatureAPI.shared.getClient() | ||
| let logger = Logger(label: "com.example.app.flags") | ||
| client.setLogger(logger) | ||
| client.setLogger(OSLogOpenFeatureLogger()) | ||
| ``` | ||
|
|
||
| **3. Evaluation-level** - affects a single flag evaluation: | ||
| ```swift | ||
| let logger = Logger(label: "com.example.app.critical-flag") | ||
| let options = FlagEvaluationOptions(logger: logger) | ||
| let options = FlagEvaluationOptions(logger: OSLogOpenFeatureLogger()) | ||
| let value = client.getBooleanValue(key: "my-flag", defaultValue: false, options: options) | ||
| ``` | ||
|
|
||
| #### Provider Support | ||
|
|
||
| Providers can optionally use the logger for debugging and diagnostics. The logger is passed to providers during flag evaluation, allowing them to log relevant information. | ||
| Providers can optionally use the logger for debugging and diagnostics. The resolved `OpenFeatureLogger` is passed to providers during flag evaluation through the `logger:` parameter of the evaluation methods, allowing them to log relevant information without depending on any logging framework. | ||
|
|
||
| If no logger is configured, logging is disabled. The logger is completely optional for both SDK users and provider authors. | ||
|
|
||
| ##### Migrating providers from swift-log (0.6.x) | ||
|
|
||
| In 0.6.x the logger-aware `FeatureProvider` methods took a swift-log `Logger?`. They now take `(any OpenFeatureLogger)?`. A provider that still declares the old signature will compile, because the method simply stops matching the protocol requirement, but the SDK will call the default implementation instead and **the provider's logging silently stops**. Update all five logger-aware methods: | ||
|
|
||
| ```swift | ||
| // Before (0.6.x) | ||
| func getBooleanEvaluation(key: String, defaultValue: Bool, context: EvaluationContext?, logger: Logger?) throws | ||
| -> ProviderEvaluation<Bool> | ||
|
|
||
| // After | ||
| func getBooleanEvaluation( | ||
| key: String, defaultValue: Bool, context: EvaluationContext?, logger: (any OpenFeatureLogger)? | ||
| ) throws -> ProviderEvaluation<Bool> | ||
| ``` | ||
|
|
||
| Apply the same change to `getStringEvaluation`, `getIntegerEvaluation`, `getDoubleEvaluation` and `getObjectEvaluation`. Inside the method, `logger?.debug(...)`, `logger?.info(...)`, `logger?.warning(...)` and `logger?.error(...)` calls that pass only a message keep working unchanged. `OpenFeatureLogger` takes just a message, so swift-log-specific arguments such as `metadata:` or `source:` no longer compile; fold that information into the message, and replace `trace`, `notice` or `critical` calls with the nearest of the four levels. Providers that only implement the plain evaluation methods (without `logger:`) need no changes. Drop the `import Logging` if the provider no longer uses swift-log directly. | ||
|
|
||
| ### Domains | ||
|
|
||
| Domains allow you to logically bind clients with providers, enabling the use of multiple providers within a single application. Each domain can have its own provider, and clients can be associated with a specific domain. | ||
|
|
@@ -317,6 +378,51 @@ let providers = [ | |
| let multiProvider = MultiProvider(providers: providers) | ||
| ``` | ||
|
|
||
| ### InMemoryProvider | ||
|
|
||
| `InMemoryProvider` resolves flags from a configuration you supply, with no network calls and no mocking. It is useful for demos, local development, and for testing hooks, providers, or application code that consumes flags. | ||
|
|
||
| ```swift | ||
| let provider = InMemoryProvider(flags: [ | ||
| "boolean-flag": InMemoryFlag( | ||
| variants: ["on": .boolean(true), "off": .boolean(false)], | ||
| defaultVariant: "on"), | ||
| "greeting": InMemoryFlag( | ||
| variants: ["formal": .string("Good evening"), "casual": .string("hi")], | ||
| defaultVariant: "formal", | ||
| flagMetadata: ["version": .string("1.0.2")]), | ||
| ]) | ||
|
|
||
| await OpenFeatureAPI.shared.setProviderAndWait(provider: provider) | ||
| OpenFeatureAPI.shared.getClient().getBooleanValue(key: "boolean-flag", defaultValue: false) // true | ||
| ``` | ||
|
|
||
| Targeting is expressed as a callback returning the key of the variant to resolve, or `nil` to fall back to the flag's `defaultVariant`: | ||
|
|
||
| ```swift | ||
| InMemoryFlag( | ||
| variants: ["internal": .string("INTERNAL"), "external": .string("EXTERNAL")], | ||
| defaultVariant: "external", | ||
| contextEvaluator: { _, context in | ||
| context?.getValue(key: "customer") == .boolean(false) ? "internal" : nil | ||
| }) | ||
| ``` | ||
|
|
||
| A resolution reports `TARGETING_MATCH` when the callback selects a variant, `DEFAULT` when it returns `nil`, `STATIC` when the flag has no callback, and `DISABLED` for a flag constructed with `disabled: true`. An unknown flag key resolves as `FLAG_NOT_FOUND`, and a variant whose value is not of the requested type as `TYPE_MISMATCH`. | ||
|
|
||
| The configuration can be changed after the provider is registered, which emits `PROVIDER_CONFIGURATION_CHANGED`: | ||
|
|
||
| ```swift | ||
| provider.updateFlag(key: "boolean-flag", flag: InMemoryFlag( | ||
| variants: ["on": .boolean(true), "off": .boolean(false)], | ||
| defaultVariant: "off")) | ||
|
|
||
| provider.removeFlag(key: "greeting") | ||
|
|
||
| // Replaces the whole configuration; the event reports the union of the old and new flag keys. | ||
| provider.putConfiguration(["only-flag": InMemoryFlag(variants: ["on": .boolean(true)], defaultVariant: "on")]) | ||
| ``` | ||
|
|
||
| ### 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. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
Repository: open-feature/openfeature.dev
Length of output: 3329
🏁 Script executed:
Repository: open-feature/openfeature.dev
Length of output: 2621
Align the Swift Package Manager example with a released SDK.
The page targets Swift SDK
0.6.0, but that release defines only theOpenFeatureproduct. It does not defineOpenFeatureSwiftLog, so the documented bridge dependency cannot resolve against the stated release.The same manifest requires
swift-logfrom the coreOpenFeaturetarget. This conflicts with the page's claims that the SDK has no third-party dependencies and that only the optional bridge usesswift-log.Use the first released SDK version whose manifest provides the bridge product and makes
swift-logoptional. If that version is not released, keep the page aligned with0.6.0until it is available.🤖 Prompt for AI Agents