[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-7499":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":17,"stars30d":18,"stars90d":16,"forks30d":16,"starsTrendScore":17,"compositeScore":19,"rankGlobal":10,"rankLanguage":10,"license":20,"archived":21,"fork":21,"defaultBranch":22,"hasWiki":23,"hasPages":21,"topics":24,"createdAt":10,"pushedAt":10,"updatedAt":35,"readmeContent":36,"aiSummary":37,"trendingCount":16,"starSnapshotCount":16,"syncStatus":38,"lastSyncTime":39,"discoverSource":40},7499,"multiplatform-settings","russhwolf\u002Fmultiplatform-settings","russhwolf","A Kotlin Multiplatform library for saving simple key-value data","",null,"Kotlin",2230,79,18,31,0,1,13,27.71,"Apache License 2.0",false,"main",true,[25,26,27,28,29,30,31,32,33,34],"kotlin","kotlin-android","kotlin-ios","kotlin-js","kotlin-jvm","kotlin-library","kotlin-multiplatform","kotlin-multiplatform-library","kotlin-native","kotlin-wasm","2026-06-12 02:01:40","[![Linux Build Status](https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Factions\u002Fworkflow\u002Fstatus\u002Frusshwolf\u002Fmultiplatform-settings\u002Fbuild-linux.yml?branch=main&label=JVM%2FJS%2FAndroid%2FLinux%20Build&logo=Linux&logoColor=black)](https:\u002F\u002Fgithub.com\u002Frusshwolf\u002Fmultiplatform-settings\u002Factions\u002Fworkflows\u002Fbuild-linux.yml)\n[![Mac Build Status](https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Factions\u002Fworkflow\u002Fstatus\u002Frusshwolf\u002Fmultiplatform-settings\u002Fbuild-macos.yml?branch=main&label=iOS%2FmacOS%2FtvOS%2FwatchOS%20Build&logo=Apple)](https:\u002F\u002Fgithub.com\u002Frusshwolf\u002Fmultiplatform-settings\u002Factions\u002Fworkflows\u002Fbuild-macos.yml)\n[![Windows Build Status](https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Factions\u002Fworkflow\u002Fstatus\u002Frusshwolf\u002Fmultiplatform-settings\u002Fbuild-windows.yml?branch=main&label=Windows%20Build&logo=Windows)](https:\u002F\u002Fgithub.com\u002Frusshwolf\u002Fmultiplatform-settings\u002Factions\u002Fworkflows\u002Fbuild-windows.yml)\n\n[![Maven Central](https:\u002F\u002Fimg.shields.io\u002Fmaven-central\u002Fv\u002Fcom.russhwolf\u002Fmultiplatform-settings?label=Maven%20Central)](https:\u002F\u002Fsearch.maven.org\u002Fartifact\u002Fcom.russhwolf\u002Fmultiplatform-settings)\n\n# Multiplatform Settings\n\nThis is a Kotlin library for Multiplatform apps, so that common code can persist key-value data.\n\nA [Korean translation](https:\u002F\u002Fgithub.com\u002Fwooram-yang\u002Fmultiplatform-settings\u002Fblob\u002Ffeature\u002Fadd_ko_readme_file\u002FREADME-ko.md)\nof this readme is available separately, maintained by @wooram-yang\n\n## Table of contents\n\n\u003C!-- TODO it's maybe getting time to break this up into separate pages and do a real docs site -->\n\n* [Usage](#usage)\n  + [Implementation Summary](#implementation-summary)\n  + [Creating a Settings instance](#creating-a-settings-instance)\n    - [Platform constructors](#platform-constructors)\n    - [Factories](#factories)\n    - [No-arg module](#no-arg-module)\n  + [Settings API](#settings-api)\n    - [Listeners](#listeners)\n    - [Testing](#testing)\n  + [Other platforms](#other-platforms)\n* [Experimental API](#experimental-api)\n  + [Experimental Implementations](#experimental-implementations)\n  + [Serialization module](#serialization-module)\n  + [Coroutine APIs](#coroutine-apis)\n    - [DataStore](#datastore)\n  + [Make-Observable module](#make-observable-module)\n* [Adding to your project](#adding-to-your-project)\n* [Building](#building)\n* [License](#license)\n\n## Usage\n\nThe `Settings` interface has implementations on the Android, iOS, macOS, watchOS, tvOS, JS, WasmJS, JVM, and Windows\nplatforms.\n\n### Implementation Summary\n\nThe following table shows the names of implementing classes and what platforms they're available on.\n\n| Class                                   | Backing API                         | Platforms                      |\n|-----------------------------------------|-------------------------------------|--------------------------------|\n| `KeychainSettings`\u003Csup>2\u003C\u002Fsup>          | Apple Keychain                      | iOS, macOS, watchOS, tvOS      |\n| `NSUserDefaultsSettings`\u003Csup>1\u003C\u002Fsup>    | User Defaults                       | iOS, macOS, watchOS, tvOS      |\n| `PreferencesSettings`\u003Csup>1\u003C\u002Fsup>       | `java.util.prefs.Preferences`       | JVM                            |\n| `PropertiesSettings`                    | `java.util.Properties`              | JVM                            |\n| `SharedPreferencesSettings`\u003Csup>1\u003C\u002Fsup> | `android.content.SharedPreferences` | Android                        |\n| `StorageSettings`                       | Web Storage (localStorage)          | JS, WasmJS                     |\n| `RegistrySettings`\u003Csup>2\u003C\u002Fsup>          | Windows Registry                    | MingwX64                       |\n| `DataStoreSettings`\u003Csup>3\u003C\u002Fsup>         | `androidx.datastore.core.DataStore` | Android, JVM, Native           |\n| `MapSettings`\u003Csup>1,4\u003C\u002Fsup>             | `kotlin.collections.MutableMap`     | All platforms                  |\n\n\u003Csup>\n\u003Csup>1\u003C\u002Fsup> Implements \u003Ccode>ObservableSettings\u003C\u002Fcode> interface\u003Cbr\u002F>\n\u003Csup>2\u003C\u002Fsup> Implementation is considered experimental\u003Cbr\u002F>\n\u003Csup>3\u003C\u002Fsup> Implements \u003Ccode>SuspendSettings\u003C\u002Fcode> and \u003Ccode>FlowSettings\u003C\u002Fcode> rather than \u003Ccode>Settings\u003C\u002Fcode> or \u003Ccode>ObservableSettings\u003C\u002Fcode>\u003Cbr\u002F>\n\u003Csup>4\u003C\u002Fsup> \u003Ccode>MapSettings\u003C\u002Fcode> is intended for use in unit tests and will not persist data to storage\n\u003C\u002Fsup>\n\n### Creating a Settings instance\n\nWhen writing multiplatform code, you might need to interoperate with platform-specific code which needs to share the\nsame data-source. To facilitate this, all `Settings` implementations wrap a delegate object which you could also use in\nyour platform code.\n\nSince that delegate is a constructor argument, it should be possible to connect it via any dependency-injection strategy\nyou might already be using. If your project doesn't have such a system already in place, one strategy is to use `expect`\ndeclarations, for example\n\n```kotlin\nexpect val settings: Settings\n\n\u002F\u002F or\nexpect fun createSettings(): Settings\n```\n\nThen the `actual` implementations can pass the platform-specific delegates.\nSee [Platform constructors](#platform-constructors) below for more details on these delegates.\n\nSome platform implementations also include `Factory` classes. These make it easier to manage multiple named `Settings`\nobjects from common code, or to automate some platform-specific configuration so that delegates don't need to be created\nmanually. The factory still needs to be injected from platform code, but then from common you can call\n\n```kotlin\nval settings1: Settings = factory.create(\"my_first_settings\")\nval settings2: Settings = factory.create(\"my_other_settings\")\n```\n\nSee [Factories](#factories) below for more details.\n\nHowever, if all of your key-value logic exists in a single instance in common code, these ways of\ninstantiation `Settings` can be inconvenient. To make pure-common usage easier, Multiplatform Settings now includes a\nseparate module which provides a `Settings()` factory function, so that you can create a `Settings` instance like\n\n```kotlin\nval settings: Settings = Settings()\n```\n\nSee [No-arg module](#no-arg-module) below for more details.\n\n#### Platform constructors\n\nThe Android implementation is `SharedPreferencesSettings`, which wraps `SharedPreferences`.\n\n```kotlin\nval delegate: SharedPreferences \u002F\u002F ...\nval settings: Settings = SharedPreferencesSettings(delegate)\n```\n\nOn iOS, macOS, tvOS, or watchOS, `NSUserDefaultsSettings` wraps `NSUserDefaults`.\n\n```kotlin\nval delegate: NSUserDefaults \u002F\u002F ...\nval settings: Settings = NSUserDefaultsSettings(delegate)\n```\n\nYou can also use `KeychainSettings` which writes to the Keychain. Construct it by passing a String which will be\ninterpreted as a service name.\n\n```kotlin\nval serviceName: String \u002F\u002F ...\nval settings: Settings = KeychainSettings(serviceName)\n```\n\nTwo JVM implementations exist. `PreferencesSettings` wraps `Preference`s and `PropertiesSettings` wraps `Properties`.\n\n```kotlin\nval delegate: Preferences \u002F\u002F ...\nval settings: Settings = PreferencesSettings(delegate)\n\nval delegate: Properties \u002F\u002F ...\nval settings: Settings = PropertiesSettings(delegate)\n```\n\nOn JS and WasmJS, `StorageSettings` wraps `Storage`.\n\n```kotlin\nval delegate: Storage \u002F\u002F ...\nval settings: Settings = StorageSettings(delegate)\n\nval settings: Settings = StorageSettings() \u002F\u002F use localStorage by default\n```\n\nThere is a Windows implementation `RegistrySettings` which wraps the Windows registry.\n\n```kotlin\nval rootKey: String = \"SOFTWARE\\\\...\" \u002F\u002F Will be interpreted as subkey of HKEY_CURRENT_USER\nval settings: Settings = RegistrySettings(rootKey)\n```\n\n#### Factories\n\nFor some platforms, a `Factory` class also exists, so that multiple named `Settings` instances can coexist with the\nnames being controlled from common code.\n\nOn Android, this factory needs a `Context` parameter\n\n```kotlin\nval context: Context \u002F\u002F ...\nval factory: Settings.Factory = SharedPreferencesSettings.Factory(context)\n```    \n\nOn most other platforms, the factory can be instantiated without passing any parameter\n\n```kotlin\nval factory: Settings.Factory = NSUserDefaultsSettings.Factory()\n```\n\nIf you have a `Factory` reference from your common code, then you can use it to create multiple `Settings` with\ndifferent names.\n\n```kotlin\nval settings1: Settings = factory.create(\"my_first_settings\")\nval settings2: Settings = factory.create(\"my_other_settings\")\n```\n\nIf the default `Factory`s don't do what you need, you can also implement your own.\n\n#### No-arg module\n\nTo create a `Settings` instance from common without needing to pass platform-specific dependencies, add\nthe `multiplatform-settings-no-arg` gradle dependency. This exports `multiplatform-settings` as an API dependency, so\nyou can use it as a replacement for that default dependency.\n\n```kotlin\nimplementation(\"com.russhwolf:multiplatform-settings-no-arg:1.3.0\")\n```\n\nThen from common code, you can write\n\n```kotlin\nval settings: Settings = Settings()\n```\n\nThis is implemented via a top-level function `Settings()` to provide constructor-like\nsyntax even though `Settings` has no constructor.\n\nOn Android, this delegates to the equivalent of `PreferenceManager.getDefaultSharedPreferences()` internally. It makes\nuse of [`androidx-startup`](https:\u002F\u002Fdeveloper.android.com\u002Fjetpack\u002Fandroidx\u002Freleases\u002Fstartup) to get a `Context`\nreference without needing to pass one manually. On Apple platforms, it uses `NSUserDefaults.standardUserDefaults`. On \nJS, it uses `localStorage`. On JVM, it uses the `Preferences` implementation with `Preferences.userRoot()` as a \ndelegate. On Windows, it reads the name of the executable being built and writes to a subkey of \n`HKEY_CURRENT_USER\\SOFTWARE` using that name.\n\nNote that while the main `multiplatform-settings` module publishes common code to all available Kotlin platforms,\nthe `multiplatform-settings-no-arg` module only publishes to platforms which have concrete implementations.\n\nNote also that the `no-arg` module is there to make getting started easier with less configuration, but there are plenty\nof things it doesn't provide, such as the ability to use an encrypted implementation on platforms that support it, or\nthe ability to substitute a test implementation. Notably, you can't call `Settings()` from an Android unit test because\nthe internals that allow it to get a `Context` reference won't run (not even if you use Robolectric).\n\nIf you need a non-default setup you likely are better off not using `multiplatform-settings-no-arg`.\n\n### Settings API\n\nOnce the `Settings` instance is created, you can store values by calling the various `putXXX()` methods, or their\noperator shortcuts\n\n```kotlin\nsettings.putInt(\"key\", 3)\nsettings[\"key\"] = 3\n```\n\nYou can retrieve stored values via the `getXXX()` methods or their operator shortcuts. If a key is not present, then the\nsupplied default will be returned instead.\n\n```kotlin\nval a: Int = settings.getInt(\"key\")\nval b: Int = settings.getInt(\"key\", defaultValue = -1)\nval c: Int = settings[\"key\", -1]\n```    \n\nNullable methods are also available to avoid the need to use a default value. Instead, `null` will be returned if a key\nis not present.\n\n```kotlin\nval a: Int? = settings.getIntOrNull(\"key\")\nval b: Int? = settings[\"key\"]\n```    \n\nThe `getXXX()` and `putXXX()` operation for a given key can be wrapped using a property delegate. This has the advantage\nof ensuring that the key is always accessed with a consistent type.\n\n```kotlin\nval a: Int by settings.int(\"key\")\nval b: Int by settings.int(\"key\", defaultValue = -1)\n```    \n\nNullable delegates exists so that absence of a key can be indicated by `null` instead of a default value\n\n```kotlin    \nval a: Int? by settings.nullableInt(\"key\")\n```    \n\nThe `key` parameter can be omitted for delegates, and the property name will be reflectively used instead.\n\n```kotlin\nval a: Int by settings.int() \u002F\u002F internally, key is \"a\"\n```\n\nExistence of a key can be queried\n\n```kotlin     \nval a: Boolean = settings.hasKey(\"key\")\nval b: Boolean = \"key\" in settings\n```\n\nValues can also be removed by key\n\n```kotlin \nsettings.remove(\"key\")\nsettings -= \"key\"\nsettings[\"key\"] = null\n``` \n\nFinally, all values in a `Settings` instance can be removed\n\n```kotlin     \nsettings.clear()\n```\n\nThe set of keys and amount of entries can be retrieved\n\n```kotlin\nval keys: Set\u003CString> = settings.keys\nval size: Int = settings.size\n```\n\nNote that for the `NSUserDefaultsSettings` implementation, some entries are unremovable and therefore may still be\npresent after a `clear()` call. Thus, `size` is not generally guaranteed to be zero after a `clear()`.\n\n#### Listeners\n\nUpdate listeners are available for some implementations. These are marked\nwith the `ObservableSettings` interface, which includes an `addListener()` method.\n\n```kotlin\nval observableSettings: ObservableSettings \u002F\u002F ...\nval settingsListener: SettingsListener = observableSettings.addIntListener(key) { value: Int -> \u002F* ... *\u002F }\nval settingsListener: SettingsListener = observableSettings.addNullableIntListener(key) { value: Int? -> \u002F* ... *\u002F }\n```\n\nThe `SettingsListener` returned from the call should be used to signal when you're done listening:\n\n```kotlin\nsettingsListener.deactivate()\n```    \n\nIf you don't hold a strong reference to the `SettingsListener`, it's possible in some implementations that it will be\ngarbage-collected and stop sending updates.\n\n#### Testing\n\nA testing dependency is available to aid in testing code that interacts with this library.\n\n```kotlin\nimplementation(\"com.russhwolf:multiplatform-settings-test:1.3.0\")\n```    \n\nThis includes a `MapSettings` implementation of the `Settings` interface, which is backed by an in-memory `MutableMap`\non all platforms.\n\n### Other platforms\n\nThe `Settings` interface is published to all available platforms. Developers who desire implementations outside of the\ndefaults provided are free to add their own implementations, and are welcome to make pull requests if the implementation\nmight be generally useful to others. Note that implementations which require external dependencies should be places in a\nseparate gradle module in order to keep the core `multiplatform-settings` module dependency-free.\n\n## Experimental API\n\nCertain APIs are marked with `@ExperimentalSettingsApi` or `@ExperimentalSettingsImplementation` to highlight areas that\nmay have the potential to break in the future and should not be considered stable to depend on.\n\n### Experimental Implementations\n\nThe `KeychainSettings` implementation on Apple platforms and the `RegistrySettings` implementation on Windows are\nconsidered experimental. Feel free to reach out if they're working well for you, or if you encounter any issues with\nthem, to help remove that experimental status.\n\n### Serialization module\n\nA `kotlinx-serialization` integration exists so it's easier to save non-primitive data\n\n```kotlin\nimplementation(\"com.russhwolf:multiplatform-settings-serialization:1.3.0\")\n```\n\nThis essentially uses the `Settings` store as a serialization format. Thus for a serializable class\n\n```kotlin\n@Serializable\nclass SomeClass(val someProperty: String, anotherProperty: Int)\n```\n\nan instance can be stored or retrieved\n\n```kotlin\nval someClass: SomeClass\nval settings: Settings\n\n\u002F\u002F Store values for the properties of someClass in settings\nsettings.encodeValue(SomeClass.serializer(), \"key\", someClass)\n\n\u002F\u002F Create a new instance of SomeClass based on the data in settings\nval newInstance: SomeClass = settings.decodeValue(SomeClass.serializer(), \"key\", defaultValue)\nval nullableNewInstance: SomeClass = settings.decodeValueOrNull(SomeClass.serializer(), \"key\")\n```\n\nTo remove a serialized value, use `removeValue()` rather than `remove()`\n\n```kotlin\nsettings.removeValue(SomeClass.serializer(), \"key\")\n\n\u002F\u002F Don't remove if not all expected data is preset\nsettings.removeValue(SomeClass.serializer(), \"key\", ignorePartial = true)\n```\n\nTo check for the existance of a serialized value, use `containsValue()` rather than `contains()`.\n\n```kotlin\nval isPresent = settings.containsValue(SomeClass.serializer(), \"key\")\n```\n\nThere's also a delegate API, similar to that for primitives\n\n```kotlin\nval someClass: SomeClass by settings.serializedValue(SomeClass.serializer(), \"someClass\", defaultValue)\nval nullableSomeClass: SomeClass? by settings.nullableSerializedValue(SomeClass.serializer(), \"someClass\")\n```\n\nAll APIs also have variants that infer a serializer implicitly rather than taking one as a parameter. These APIs throw\nif the class is not serializable.\n\n```kotlin\nsettings.encodeValue(\"key\", someClass)\nval newInstance: SomeClass = settings.decodeValue(\"key\", defaultValue)\nval nullableNewInstance: SomeClass = settings.decodeValueOrNull(\"key\")\n\u002F\u002F etc\n```\n\nUsage requires accepting both the `@ExperimentalSettingsApi` and `@ExperimentalSerializationApi` annotations.\n\n### Coroutine APIs\n\nA separate `multiplatform-settings-coroutines` dependency includes various coroutine APIs.\n\n```kotlin\nimplementation(\"com.russhwolf:multiplatform-settings-coroutines:1.3.0\")\n```\n\nThis adds flow extensions for all types which use the listener APIs internally.\n\n```kotlin\nval observableSettings: ObservableSettings \u002F\u002F Only works with ObservableSettings\n\nval flow: Flow\u003CInt> by observableSettings.getIntFlow(\"key\", defaultValue)\nval nullableFlow: Flow\u003CInt?> by observableSettings.getIntOrNullFlow(\"key\")\n```\n\nThere are also `StateFlow` extensions, which require a coroutine scope.\n\n```kotlin\nval observableSettings: ObservableSettings \u002F\u002F Only works with ObservableSettings\nval coroutineScope: CoroutineScope\n\nval stateFlow: StateFlow\u003CInt> by observableSettings.getIntStateFlow(\"key\", defaultValue)\nval nullableStateFlow: StateFlow\u003CInt?> by observableSettings.getIntOrNullStateFlow(\"key\")\n```\n\nIn addition, there are two new `Settings`-like interfaces: `SuspendSettings`, which looks similar to `Settings` but all\nfunctions are marked `suspend`, and `FlowSettings` which extends `SuspendSettings` to also include `Flow`-based getters\nsimilar to the extensions mentioned above.\n\n```kotlin\nval suspendSettings: SuspendSettings \u002F\u002F ...\nval a: Int = suspendSettings.getInt(\"key\") \u002F\u002F This call will suspend\n\nval flowSettings: FlowSettings \u002F\u002F ...\nval flow: Flow\u003CInt> = flowSettings.getIntFlow(\"key\")\n```\n\nThere are APIs provided to convert between these different interfaces so that you can select one to use primarily from\ncommon.\n\n```kotlin\nval settings: Settings \u002F\u002F ...\nval suspendSettings: SuspendSettings = settings.toSuspendSettings()\n\nval observableSettings: ObservableSettings \u002F\u002F ...\nval flowSettings: FlowSettings = observableSettings.toFlowSettings()\n\n\u002F\u002F Wrap suspend calls in runBlocking\nval blockingSettings: Settings = suspendSettings.toBlockingSettings()\nval blockingSettings: ObservableSettings = flowSettings.toBlockingObservableSettings()\n```\n\n#### DataStore\n\nAn implementation of `FlowSettings` exists in the `multiplatform-settings-datastore` dependency, based\non [Jetpack DataStore](https:\u002F\u002Fdeveloper.android.com\u002Fjetpack\u002Fandroidx\u002Freleases\u002Fdatastore). Because DataStore is now a\nmultiplatform library, starting in version 1.2.0, this module is available on all platforms where DataStore is\navailable, rather than being limited to Android and JVM.\n\n```kotlin\nimplementation(\"com.russhwolf:multiplatform-settings-datastore:1.3.0\")\n```\n\nThis provides a `DataStoreSettings` class\n\n```kotlin\nval dataStore: DataStore \u002F\u002F = ...\nval settings: FlowSettings = DataStoreSettings(dataStore)\n```\n\nYou can use this in shared code by converting other `ObservableSettings` instances to `FlowSettings`. For example:\n\n```kotlin\n\u002F\u002F Common\nexpect val settings: FlowSettings\n\n\u002F\u002F Android\nactual val settings: FlowSettings = DataStoreSettings(\u002F*...*\u002F)\n\n\u002F\u002F iOS\nactual val settings: FlowSettings = NSUserDefaultsSettings(\u002F*...*\u002F).toFlowSettings()\n```\n\nOr, if you also include platforms without listener support, you can use `SuspendSettings` instead.\n\n```kotlin\n\u002F\u002F Common\nexpect val settings: SuspendSettings\n\n\u002F\u002F Android\nactual val settings: SuspendSettings = DataStoreSettings(\u002F*...*\u002F)\n\n\u002F\u002F iOS\nactual val settings: SuspendSettings = NSUserDefaultsSettings(\u002F*...*\u002F).toSuspendSettings()\n\n\u002F\u002F JS\nactual val settings: SuspendSettings = StorageSettings().toSuspendSettings()\n```\n\n### Make-Observable module\n\nThe experimental `multiplatform-settings-make-observable` module adds an extension function `Settings.makeObservable()`\nin common code which converts a `Settings` instance to `ObservableSettings` by directly wiring in callbacks rather than\nnative observability methods.\n\n```kotlin\nval settings: Settings \u002F\u002F = ...\nval observableSettings: ObservableSettings = settings.makeObservable()\n```\n\nThis has the advantage of enabling observability on platforms which don't have an observable implementation. It has the\ndisadvantage that updates will only be delivered to the same instance where changes were made.\n\n## Adding to your project\n\nMultiplatform Settings is currently published to Maven Central, so add that to repositories.\n\n```kotlin\nrepositories {\n  mavenCentral()\n  \u002F\u002F ...\n}\n```\n\nThen, simply add the dependency to your common source-set dependencies\n\n```kotlin\ncommonMain {\n  dependencies {\n    \u002F\u002F ...\n    implementation(\"com.russhwolf:multiplatform-settings:1.3.0\")\n  }\n}\n``` \n\nSee also the sample project, which uses this structure.\n\n## Building\n\nThe project includes multiple CI jobs configured using Github Actions. On PRs or updates to the `main` branch, the build\nwill run the scripts in `build-linux.yml`, `build-macos.yml`, `build-windows.yml`, and `validate-gradle-wrapper.yml`.\nThese builds the library and runs unit tests for all platforms across Linux, Mac, and Windows hosts. In addition, the\nlibrary build artifacts are deployed to the local maven repository and the sample project is built for the platforms on\nwhich it is implemented. This ensures that the sample remains in sync with updates to the library.\n\nAn addition build script is defined in `deploy.yml`, which runs on a manual trigger. This builds the library for all\nplatforms and uploads artifacts to staging on Maven Central. Uploaded artifacts must still be published manually\n\n## License\n\n    Copyright 2018-2023 Russell Wolf\n    \n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n    \n       http:\u002F\u002Fwww.apache.org\u002Flicenses\u002FLICENSE-2.0\n    \n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n\n#\n\n[![Jetbrains Logo](images\u002Fjetbrains.png)](https:\u002F\u002Fwww.jetbrains.com\u002F?from=Multiplatform-Settings)\n\nMade with JetBrains tools \n","Multiplatform Settings 是一个用于多平台应用的Kotlin库，支持在不同平台上保存简单的键值对数据。其核心功能包括跨Android、iOS、macOS、watchOS、tvOS、JS、WasmJS、JVM和Windows等平台的一致性存储解决方案，并提供了多种实现方式如KeychainSettings和NSUserDefaultsSettings来适配不同操作系统的需求。此外，该项目还引入了实验性的API如序列化模块与协程API以增强数据处理能力。适用于需要在多个平台上共享配置或用户偏好设置的应用开发场景中，确保了代码复用性和维护效率。",2,"2026-06-11 03:12:47","top_language"]