{"id":28724175,"url":"https://github.com/featurevisor/featurevisor-swift","last_synced_at":"2025-06-15T10:09:24.073Z","repository":{"id":183305484,"uuid":"667501647","full_name":"featurevisor/featurevisor-swift","owner":"featurevisor","description":"Swift SDK for Featurevisor","archived":false,"fork":false,"pushed_at":"2025-05-30T05:06:32.000Z","size":336,"stargazers_count":3,"open_issues_count":2,"forks_count":4,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-05-30T06:38:02.155Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://featurevisor.com","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/featurevisor.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"docs/contributing.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2023-07-17T16:41:58.000Z","updated_at":"2025-05-30T05:06:36.000Z","dependencies_parsed_at":null,"dependency_job_id":"a40b101c-72ab-45d2-a8b5-caed93bde762","html_url":"https://github.com/featurevisor/featurevisor-swift","commit_stats":null,"previous_names":["featurevisor/featurevisor-swift"],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/featurevisor/featurevisor-swift","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/featurevisor%2Ffeaturevisor-swift","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/featurevisor%2Ffeaturevisor-swift/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/featurevisor%2Ffeaturevisor-swift/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/featurevisor%2Ffeaturevisor-swift/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/featurevisor","download_url":"https://codeload.github.com/featurevisor/featurevisor-swift/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/featurevisor%2Ffeaturevisor-swift/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259957280,"owners_count":22937549,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-06-15T10:09:22.551Z","updated_at":"2025-06-15T10:09:24.058Z","avatar_url":"https://github.com/featurevisor.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Featurevisor](./assets/banner-bordered.png)](https://featurevisor.com)\n\n\u003cdiv align=\"center\"\u003e\n  \u003ch3\u003e\u003cstrong\u003eFeature management for developers\u003c/strong\u003e\u003c/h3\u003e\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003csmall\u003eManage your feature flags and experiments declaratively from the comfort of your Git workflow.\u003c/small\u003e\n\u003c/div\u003e\n\n\u003cbr /\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003c!-- License --\u003e\n  \u003ca href=\"./LICENSE\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/l/@featurevisor/sdk.svg?style=flat-square\"\n      alt=\"License\" /\u003e\n  \u003c/a\u003e\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003ch3\u003e\n    \u003ca href=\"https://featurevisor.com\"\u003e\n      Website\n    \u003c/a\u003e\n    \u003cspan\u003e | \u003c/span\u003e\n    \u003ca href=\"https://featurevisor.com/docs\"\u003e\n      Documentation\n    \u003c/a\u003e\n    \u003cspan\u003e | \u003c/span\u003e\n    \u003ca href=\"https://github.com/featurevisor/featurevisor-swift/issues\"\u003e\n      Issues\n    \u003c/a\u003e\n    \u003cspan\u003e | \u003c/span\u003e\n    \u003ca href=\"https://featurevisor.com/docs/contributing\"\u003e\n      Contributing\n    \u003c/a\u003e\n    \u003cspan\u003e | \u003c/span\u003e\n  \u003c/h3\u003e\n\u003c/div\u003e\n\n---\n\n# featurevisor-swift\n\nThis repository is a port of the [Featurevisor](https://featurevisor.com) JavaScript SDK to Swift.\n\n## Installation\n\n### Swift Package Manager\n\nThe [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler.\n\nOnce you have your Swift package set up, adding Featurevisor as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift`.\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/featurevisor/featurevisor-swift.git\", .upToNextMajor(from: \"X.Y.Z\"))\n]\n```\n\n## Usage\n\n### Setting up Featurevisor SDK\nWe would like to be able to set up the Featurevisor SDK instance once and reuse the same instance everywhere.\n\nThe SDK can be initialized in two different ways depending on your needs.\n\n### Synchronous\nYou can fetch the datafile content on your own and just pass it via options.\n\n```swift\nimport FeaturevisorSDK\n\nlet datafileContent: DatafileContent = ...\nvar options: InstanceOptions = .default\noptions.datafile = datafileContent\n\nlet f = try createInstance(options: options)\n```\n\n### Asynchronous\nIf you want to delegate the responsibility of fetching the datafile to the SDK.\n\n```swift\nimport FeaturevisorSDK\n\nvar options: InstanceOptions = .default\noptions.datafileUrl = \"https://cdn.yoursite.com/production/datafile-tag-all.json\" \nlet f = try createInstance(options: options)\n```\n\nIf you need to take further control on how the datafile is fetched, you can pass a custom `handleDatafileFetch` function\n\n```swift\npublic typealias DatafileFetchHandler = (_ datafileUrl: String) -\u003e Result\u003cDatafileContent, Error\u003e\n```\n\n```swift\nimport FeaturevisorSDK\n\nvar options: InstanceOptions = .default\noptions.handleDatafileFetch = { datafileUrl in\n    // you need to return here Result\u003cDatafileContent, Error\u003e\n}\nlet f = try createInstance(options: options)\n```\n\n### Context\nContexts are a set of attribute values that we pass to SDK for evaluating features.\n\nThey are objects where keys are the attribute keys, and values are the attribute values.\n\n```swift\npublic enum AttributeValue {\n    case string(String)\n    case integer(Int)\n    case double(Double)\n    case boolean(Bool)\n    case date(Date)\n```\n\n```swift\nlet context = [\n  \"myAttributeKey\": .string(\"myStringAttributeValue\"),\n  \"anotherAttributeKey\": .double(0.999),\n]\n```\n\n### Checking if enabled\nOnce the SDK is initialized, you can check if a feature is enabled or not:\n\n```swift\nlet featureKey = \"my_feature\";\nlet context = [\n    \"userId\": .string(\"123\"),\n    \"country\": .string(\"nl\")\n]\n\nlet isEnabled = f.isEnabled(featureKey: featureKey, context: context)\n```\n\n### Getting variations\nIf your feature has any variations defined, you can get evaluate them as follows\n\n```swift\nlet featureKey = \"my_feature\";\nlet context = [\n    \"userId\": .string(\"123\")\n]\n\nlet variation = f.getVariation(featureKey: featureKey, context: context)\n```\n\n### Getting variables\n```swift\nlet featureKey = \"my_feature\";\nlet variableKey = \"color\"\nlet context = [\n    \"userId\": .string(\"123\")\n]\nlet variable: VariableValue? = f.getVariable(featureKey: featureKey, variableKey: variableKey, context: context)\n```\n\n### Type specific methods\n\n#### Boolean\n```swift\nlet booleanVariable: Bool? = f.getVariableBoolean(featureKey: FeatureKey, variableKey: VariableKey, context: Context)\n```\n\n#### String\n```swift\nlet stringVariable: String? = f.getVariableString(featureKey: FeatureKey, variableKey: VariableKey, context: Context)\n```\n\n#### Integer\n```swift\nlet integerVariable: Int? = f.getVariableInteger(featureKey: FeatureKey, variableKey: VariableKey, context: Context)\n```\n\n#### Double\n```swift\nlet doubleVariable: Double? = f.getVariableDouble(featureKey: FeatureKey, variableKey: VariableKey, context: Context)\n```\n\n#### Array of strings\n```swift\nlet arrayVariable: [String]? = f.getVariableArray(featureKey: FeatureKey, variableKey: VariableKey, context: Context)\n```\n\n#### Generic decodable object\n```swift\nlet objectVariable: MyDecodableObject? = f.getVariableObject(featureKey: FeatureKey, variableKey: VariableKey, context: Context)\n```\n\n#### JSON object\n```swift\nlet jsonVariable: MyJSONDecodableObject? = f.getVariableJSON(featureKey: FeatureKey, variableKey: VariableKey, context: Context)\n```\n\n### Logging\nBy default, Featurevisor will log logs in console output window for `warn` and `error` levels.\n\n#### Level\n```swift\nlet logger = createLogger(levels: [.error, .warn, .info, .debug])\n```\n#### Handler\n```swift\nlet logger = createLogger(\n        levels: [.error, .warn, .info, .debug],\n        handle: { level, message, details in ... })\n\nvar options = InstanceOptions.default\noptions.logger = logger\n\nlet f = try createInstance(options: options)\n```\n\n### Refreshing datafile\nRefreshing the datafile is convenient when you want to update the datafile in runtime, for example when you want to update the feature variations and variables config without having to restart your application.\n\nIt is only possible to refresh datafile in Featurevisor if you are using the datafileUrl option when creating your SDK instance.\n\n#### Manual refresh\n\n```swift\nf.refresh()\n```\n\n#### Refresh by interval\nIf you want to refresh your datafile every X number of seconds, you can pass the `refreshInterval` option when creating your SDK instance:\n\n```swift\nimport FeaturevisorSDK\n\nvar options: InstanceOptions = .default\noptions.datafileUrl = \"https://cdn.yoursite.com/production/datafile-tag-all.json\"\noptions.refreshInterval = 30 // 30 seconds\n\nlet f = try createInstance(options: options)\n```\n\nYou can stop the interval by calling\n\n```swift\nf.stopRefreshing()\n```\n\nIf you want to resume refreshing\n\n```swift\nf.startRefreshing()\n```\n\n### Listening for updates\nEvery successful refresh will trigger the `onRefresh` option\n\n```swift\nimport FeaturevisorSDK\n\nvar options: InstanceOptions = .default\noptions.datafileUrl = \"https://cdn.yoursite.com/production/datafile-tag-all.json\"\noptions.onRefresh = { ... }\n\nlet f = try createInstance(options: options)\n```\n\nNot every refresh is going to be of a new datafile version. If you want to know if datafile content has changed in any particular refresh, you can listen to `onUpdate` option\n\n```swift\nimport FeaturevisorSDK\n\nvar options: InstanceOptions = .default\noptions.datafileUrl = \"https://cdn.yoursite.com/production/datafile-tag-all.json\"\noptions.onUpdate = { ... }\n\nlet f = try createInstance(options: options)\n```\n\n### Events\nFeaturevisor SDK implements a simple event emitter that allows you to listen to events that happen in the runtime.\n\n#### Listening to events\nYou can listen to these events that can occur at various stages in your application\n\n##### ready\nWhen the SDK is ready to be used if used in an asynchronous way involving datafileUrl option\n\n```swift\nimport FeaturevisorSDK\n\nvar options: InstanceOptions = .default\noptions.datafileUrl = \"https://cdn.yoursite.com/production/datafile-tag-all.json\"\noptions.onReady = { ... }\n\nlet f = try createInstance(options: options)\n```\n\nYou can also synchronously check if the SDK is ready\n```swift\nguard f.isReady() else {\n  // sdk is not ready to be used\n}\n```\n\n##### activation\nWhen a feature is activated\n\n```swift\nimport FeaturevisorSDK\n\nvar options: InstanceOptions = .default\noptions.datafileUrl = \"https://cdn.yoursite.com/production/datafile-tag-all.json\"\noptions.onActivation = { ... }\n\nlet f = try createInstance(options: options)\n```\n\n### CLI\n\nTo install it locally use below commands. Note, we use featurevisor-swift to avoid conflicts with other Featurevisor CLIs\n\n```bash\n$ cd path/to/featurevisor-swift-sdk\n$ swift build -c release\n$ cd .build/release\n$ cp -f Featurevisor /usr/local/bin/featurevisor-swift\n```\n\nNow you can usage like below:\n```bash\n$ cd path/to/featurevisor-project-with-yamls\n$ featurevisor-swift test .\n```\n\nTo install via Swift Package Manager, you need to add it as a dependency under your `Package.swift` file , where `X.X.X` is the version which you want to use.\n\n```swift\ndependencies: [\n    .package(\n            url: \"https://github.com/featurevisor/featurevisor-swift\", \n            exact: \"X.X.X\"\n    )\n]\n```\n\nTo run use below command:\n\n```bash\n$ swift run featurevisor test .\n```\n\nTo update the swift's featurevisor use below command:\n\n```bash\n$ swift package update\n```\n\n### Tests\nIf you would like to test your feature/s setup against Swift SDK you can do this by invoking the below command.\nCurrently, it takes all features which are being supported by `ios` and `tvos` and run tests for them.\n\n```bash\n$ swift run featurevisor test .\n```\n\n#### Options\n\n```bash\n'only-failures'\n```\n\nIf you are interested to see only the test specs that fail:\n\nExample command:\n\n```\n$ swift run featurevisor test --only-failures .\n```\n\n### Benchmarking\nYou can measure how fast or slow your SDK evaluations are for particular features.\n\nThe `--n` option is used to specify the number of iterations to run the benchmark for.\n\n### Feature\nTo benchmark evaluating a feature itself if it is enabled or disabled via SDK's `.isEnabled()` method:\n\n```bash\n featurevisor-swift benchmark \\\n  --environment staging \\\n  --feature feature_key \\\n  --context '{\"user_id\":\"123\"}' \\\n  -n 100\n```\n\n### Variation\nTo benchmark evaluating a feature's variation via SDKs's `.getVariation()` method:\n\n```bash\n featurevisor-swift benchmark \\\n  --environment staging \\\n  --feature feature_key \\\n  --context '{\"user_id\":\"123\"}' \\\n  --variation \\\n  -n 100\n```\n\n### Variable\nTo benchmark evaluating a feature's variable via SDKs's `.getVariable()` method:\n\n```bash\n featurevisor-swift benchmark \\\n  --environment staging \\\n  --feature feature_key \\\n  --variable variable_key \\\n  --context '{\"user_id\":\"123\"}' \\\n  -n 100\n```\n\n### Evaluate\nTo learn why certain values (like feature and its variation or variables) are evaluated as they are against provided [context](https://featurevisor.com/docs/sdks/javascript/#context):\n\n```bash\n featurevisor-swift evaluate \\\n  --environment staging \\\n  --feature feature_key \\\n  --context '{\"user_id\":\"123\"}' \\\n```\nThis will show you full [evaluation details](https://featurevisor.com/docs/sdks/javascript/#evaluation-details) helping you debug better in case of any confusion.\nIt is similar to logging in SDKs with debug level. But here instead, we are doing it at CLI directly in our Featurevisor project without having to involve our application(s).\n\n## License\n\n[MIT](./LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffeaturevisor%2Ffeaturevisor-swift","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffeaturevisor%2Ffeaturevisor-swift","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffeaturevisor%2Ffeaturevisor-swift/lists"}