{"id":16482810,"url":"https://github.com/shaps80/appmanifest","last_synced_at":"2025-10-27T17:31:57.611Z","repository":{"id":37595497,"uuid":"505516485","full_name":"shaps80/AppManifest","owner":"shaps80","description":null,"archived":false,"fork":false,"pushed_at":"2022-06-21T21:49:47.000Z","size":32,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-01T07:23:09.457Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shaps80.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-06-20T16:25:35.000Z","updated_at":"2022-11-13T00:29:22.000Z","dependencies_parsed_at":"2022-09-09T12:40:21.209Z","dependency_job_id":null,"html_url":"https://github.com/shaps80/AppManifest","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shaps80%2FAppManifest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shaps80%2FAppManifest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shaps80%2FAppManifest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shaps80%2FAppManifest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shaps80","download_url":"https://codeload.github.com/shaps80/AppManifest/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238535881,"owners_count":19488613,"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":"2024-10-11T13:12:06.269Z","updated_at":"2025-10-27T17:31:57.257Z","avatar_url":"https://github.com/shaps80.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"![watchOS](https://img.shields.io/badge/watchOS-DE1F51)\n![macOS](https://img.shields.io/badge/macOS-EE751F)\n![tvOS](https://img.shields.io/badge/tvOS-00B9BB)\n![ios](https://img.shields.io/badge/iOS-0C62C7)\n\n# AppManifest\n\nIntroducing **AppManifest**, a library for defining your app's deployed environment configuration.\n\nInspired by the Swift Package manifest and SwiftUI APIs, the library aims to provide a type-safe manifest of the available environments, the conditions in which they're available and even custom settings that will be applied when using that environment.\n\n## Usage\n\nUsing a `resultBuilder` it couldn't be easier to define your `Environment`'s:\n\n```swift\nlet config = AppConfiguration {\n    Environment(name: \"Dev\", configuration: .debug)\n    Environment(name: \"Test\", distribution: .testFlight)\n    Environment(name: \"Release\", distribution: .appStore)\n}\n```\n\nAs you can see a unique name must be provided as well as any conditions (`distribution` or `configuration`) where the specified `Environment` is available. This allows you to define all of your `Environment`'s up-front and let the configuration decide which is the `preferredEnvironment` automatically.\n\n\u003e You can review the AppConfiguration header-docs for details on how priority is determined, however in most cases the behaviour should be 'as expected'. You can also review the unit tests to see working implementations.\n\nIts also common to have `Environment` specific settings like API keys, URLs and more. The library provides a familiar `SwiftUI.Environment` style API, making it easy to learn and extend for your own needs.\n\n```swift\nEnvironment(name: \"Release\", distribution: .appStore)\n    .setting(\\.remoteUrl, URL(string: \"https://api.com\"))\n```\n\n\u003e The library provides a default implementation of `remoteUrl` for you.\n\u003e See below for more details on how to create your own settings.\n\nOnce you have configured your `Environment`'s and any associated settings, you can use the configuration to determine the most appropriate `Environment` in the current context (e.g. AppStore, Debug, etc)\n\n```swift\n// Dev when in DEBUG\n// Test when installed via TestFlight\n// Release when installed via the AppStore\nconfig.preferredEnvironment\n```\n\n## Custom Settings\n\nYou can create custom setting values by extending `SettingValues` similarly to how you would extend the `SwiftUI.EnvironmentValues`.\n\n```swift\nprivate struct MySettingKey: SettingKey {\n    static let defaultValue: String = \"foo\"\n}\n\nextension SettingValues {\n    var myCustomValue: String {\n        get { self[MySettingKey.self] }\n        set { self[MySettingKey.self] = newValue }\n    }\n}\n```\n\nYou can then apply the setting to your `Environment`:\n\n```swift\nEnvironment(name: \"Dev\") { }\n    .setting(\\.myCustomValue, \"bar\")\n```\n\n## SwiftUI\n\nIf you need to access settings from your current `Environment` the library also provides a convenient dynamic `PropertyWrapper` that will cause your `View` to update whenever the associated setting changes:\n\n```swift\n@EnvironmentSetting(\\.myCustomValue) private var value // \"bar\"\n```\n\nIn order for this to behave correctly however you will need to inject the `Environment` somewhere at the top-level of your `View` hierarchy. Ommitting this step will throw an **assertion**.\n\n```swift\n@main\nstruct DemoApp: App {\n    var body: some Scene {\n        ContentView()\n            .environment(\\.deployedEnvironment, config.preferredEnvironment)\n    }\n}\n```\n\n\u003e Note `deployedEnvironment` is a pre-defined `EnvironmentKey` you **must** use in order for the property wrapper to function.\n\n## Custom Distribution and Configuration\n\nThe library includes the most common distributions:\n\n- AppStore\n- TestFlight\n- Debugger (Xcode, lldb, etc.)\n\nand Configurations\n\n- Debug\n- Release\n\nBut you can also extend the library to support your own custom types:\n\n```swift\nstruct Beta: Configuration {\n    // Lets make it active whenever `BETA` has been defined\n    var isActive: Bool { \n        #if BETA\n        return true\n        #else\n        return false\n        #endif\n    }\n}\n```\n\nTaking inspiration from SwiftUI style modifiers:\n\n```swift\nextension Configuration where Self == Beta {\n    static var beta: Self { .init() }\n}\n```\n\nWe can now use this to define an `Environment`:\n\n```swift\nEnvironment(name: \"Beta\", configuration: .beta)\n```\n\n\u003e The process for creating a custom `Distribution` is identical.\n\n## Installation\n\nYou can install manually (by copying the files in the `Sources` directory) or using Swift Package Manager (**preferred**)\n\nTo install using Swift Package Manager, add this to the `dependencies` section of your `Package.swift` file:\n\n`.package(url: \"https://github.com/shaps80/AppManifest.git\", .upToNextMinor(from: \"1.0.0\"))`","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshaps80%2Fappmanifest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshaps80%2Fappmanifest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshaps80%2Fappmanifest/lists"}