{"id":17934070,"url":"https://github.com/jonnybeegod/cloudkitfeaturetoggles","last_synced_at":"2025-08-15T16:30:38.134Z","repository":{"id":100667599,"uuid":"231729188","full_name":"JonnyBeeGod/CloudKitFeatureToggles","owner":"JonnyBeeGod","description":"Native CloudKit Feature-Toggles written in Swift","archived":false,"fork":false,"pushed_at":"2020-01-06T18:01:21.000Z","size":47,"stargazers_count":5,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-10-28T21:51:08.334Z","etag":null,"topics":["cloudkit","feature-switcher","feature-switches","feature-toggle","feature-toggles","ios","swift","swift-package-manager"],"latest_commit_sha":null,"homepage":"","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/JonnyBeeGod.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-01-04T08:00:21.000Z","updated_at":"2024-04-28T00:01:49.000Z","dependencies_parsed_at":"2023-05-16T16:00:11.375Z","dependency_job_id":null,"html_url":"https://github.com/JonnyBeeGod/CloudKitFeatureToggles","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JonnyBeeGod%2FCloudKitFeatureToggles","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JonnyBeeGod%2FCloudKitFeatureToggles/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JonnyBeeGod%2FCloudKitFeatureToggles/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JonnyBeeGod%2FCloudKitFeatureToggles/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JonnyBeeGod","download_url":"https://codeload.github.com/JonnyBeeGod/CloudKitFeatureToggles/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":229927123,"owners_count":18145865,"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":["cloudkit","feature-switcher","feature-switches","feature-toggle","feature-toggles","ios","swift","swift-package-manager"],"created_at":"2024-10-28T21:43:59.103Z","updated_at":"2024-12-16T08:16:25.211Z","avatar_url":"https://github.com/JonnyBeeGod.png","language":"Swift","readme":"# CloudKit FeatureToggles\n\n![](https://github.com/JonnyBeeGod/CloudKitFeatureToggles/workflows/Swift/badge.svg)\n[![codecov](https://codecov.io/gh/JonnyBeeGod/CloudKitFeatureToggles/branch/master/graph/badge.svg?token=SVdBIFs2Lb)](https://codecov.io/gh/JonnyBeeGod/CloudKitFeatureToggles)\n\u003cimg src=\"https://img.shields.io/badge/Swift-5.1-orange.svg\" /\u003e\n\u003ca href=\"https://swift.org/package-manager\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/swiftpm-compatible-brightgreen.svg?style=flat\" alt=\"Swift Package Manager\" /\u003e\n\u003c/a\u003e\n\u003cimg src=\"https://img.shields.io/badge/platforms-iOS-brightgreen.svg?style=flat\" alt=\"iOS\" /\u003e\n\u003ca href=\"https://twitter.com/jonezdotcom\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/twitter-@jonezdotcom-blue.svg?style=flat\" alt=\"Twitter: @jonezdotcom\" /\u003e\n\u003c/a\u003e\n\n## What does it do?\nFeature Toggles offer a way to enable or disable certain features that are present in your codebase, switch environments or configurations or toggle between multiple implementations of a protocol - even in your live system at runtime. *CloudKit FeatureToggles* are implemented using `CloudKit` and are therefor associated with no run costs for the developer. Existing Feature Toggles can be changed in the [CloudKit Dashboard](https://icloud.developer.apple.com/dashboard/) and are delivered immediately via silent push notifications to your users.\n\n## How to install?\nCloudKitFeatureToggles is compatible with Swift Package Manager. To install, simply add this repository URL to your swift packages as package dependency in Xcode. \nAlternatively, add this line to your `Package.swift` file:\n\n```\ndependencies: [\n    .package(url: \"https://github.com/JonnyBeeGod/CloudKitFeatureToggles\", from: \"0.1.0\")\n]\n```\n\nAnd don't forget to add the dependency to your target(s). \n\n## How to use?\n\n### CloudKit Preparations\n1. If your application does not support CloudKit yet start with adding the `CloudKit` and `remote background notification` entitlements to your application\n2. Add a new custom record type 'FeatureStatus' with two fields:\n\n| Field | Type |\n| --- | --- |\n| `featureName` | `String` |\n| `isActive` | `Int64` |\n\nFor each feature toggle you want to support in your application later add a new record in your CloudKit *public database*. \n\n### In your project\n1. In your AppDelegate, initialize a `FeatureToggleApplicationService` and hook its two `UIApplicationDelegate` methods into the AppDelegate lifecycle like so: \n\n```\nfunc application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -\u003e Bool {\n        // Override point for customization after application launch.\n        return featureToggleApplicationService.application(application, didFinishLaunchingWithOptions: launchOptions)\n}\nfunc application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -\u003e Void) {\n        featureToggleApplicationService.application(application, didReceiveRemoteNotification: userInfo, fetchCompletionHandler: completionHandler)\n}\n\n```\n2. Anywhere in your code you can create an instance of `FeatureToggleUserDefaultsRepository` and call `retrieve` to fetch the current status of a feature toggle.\n\n\u003e :warning: Note that `retrieve` returns the locally saved status of your toggle, this command does not trigger a fetch from CloudKit. Feature Toggles are fetched from CloudKit once at app start from within the `FeatureToggleApplicationService` `UIApplicationDelegate` hook. Additionally you can subscribe to updates whenever there was a change to the feature toggles in CloudKit as shown in the next section. \n\n3. You have to call `retrieve` with your implementation of a `FeatureToggleIdentifiable`. What I think works well is creating an enum which implements `FeatureToggleIdentifiable`:\n\n```\nenum FeatureToggle: String, FeatureToggleIdentifiable {\n        case feature1\n        case feature2\n        \n        var identifier: String {\n            return self.rawValue\n        }\n        \n        var fallbackValue: Bool {\n            switch self {\n            case .feature1:\n                return false\n            case .feature2:\n                return true\n            }\n        }\n    }\n``` \n### Notifications\n\nYou can subscribe to updates from your feature toggles in CloudKit by subscribing to the `onRecordsUpdated` Notification like so:\n\n```\nNotificationCenter.default.addObserver(self, selector: #selector(updateToggleStatusFromNotification), name: NSNotification.Name.onRecordsUpdated, object: nil)\n```\n\n```\n@objc\nprivate func updateToggleStatusFromNotification(notification NSNotification) {\n    guard let updatedToggles = notification.userInfo[Notification.featureToggleUserInfoKey] as? [FeatureToggle] else {\n        return\n    }\n    \n    // do something with the updated toggle like e.g. disabling UI elements \n}\n```\n\nNote that the updated Feature Toggles are attached to the notifications userInfo dictionary. When this notification has been sent the updated values are also already stored in the repository.   \n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonnybeegod%2Fcloudkitfeaturetoggles","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjonnybeegod%2Fcloudkitfeaturetoggles","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjonnybeegod%2Fcloudkitfeaturetoggles/lists"}