This content originally appeared on DEV Community and was authored by Russell Wolf
The first version of Multiplatform Settings was released in May 2018. At that time I imagined I would leave it in some form of prerelease 0.x state until Kotlin/Native and Kotlin Multiplatform were fully stable. But it's been over four years now, and plenty of other libraries in the ecosystem have gone 1.0. With the Kotlin Multiplatform Mobile beta on the horizon, I've decided it's about time for Multiplatform Settings to have a stable release.
In preparation for that, I recently released version 1.0.0-alpha01
. This includes a number of breaking changes in order to make the API a bit more consistent and intuitive. I've done my best to provide migration aids in the form of @Deprecated
annotations which in most cases will allow users to update automatically. But if for some reason you're not ready to do that, version 0.9
was also released recently with almost all the same functionality and none of the breakage.
If you've never heard of Multiplatform Settings or you'd like to take a closer look, be sure check it out on Github!
russhwolf / multiplatform-settings
A Kotlin Multiplatform library for saving simple key-value data
Multiplatform Settings
This is a Kotlin library for Multiplatform apps, so that common code can persist key-value data.
Table of contents
Adding to your project
Multiplatform Settings is currently published to Maven Central, so add that to repositories.
repositories {
mavenCentral()
// ...
}
Then, simply add the dependency to your common source-set dependencies
commonMain {
dependencies {
// ...
implementation("com.russhwolf:multiplatform-settings:0.9")
}
}
See also the sample project, which uses this structure.
Usage
The Settings
interface has implementations on the Android, iOS, macOS, watchOS, tvOS, JS, JVM, and Windows platforms. (Note that the two JVM implementations and the Windows implementation are currently marked as experimental.)
Creating a Settings instance
…
Breaking Changes
Here's a quick tour of breaking changes and other updates so you know what to expect.
Implementation class renames
In the early days, there was generally a single implementation of the Settings
class per platform, so I gave them names like AndroidSettings
, AppleSettings
, and JsSettings
. This naming scheme couldn't really hold as more implementations like KeychainSettings
and DataStoreSettings
were added. For the sake of consistency, for 1.0 the platform-based names are all being changed to mark the backing API that the implementation uses. The full list of renames is below.
Old name | New name |
---|---|
AndroidSettings | SharedPreferencesSettings |
AppleSettings | NSUserDefaultsSettings |
JvmPreferencesSettings | PreferencesSettings |
JvmPropertiesSettings | PropertiesSettings |
WindowsSettings | RegistrySettings |
MockSettings | MapSettings |
Update listener changes
The original ObservableSettings
interface was based around an untyped addListener()
function, with the consumer responsible for reading out the current value at the observed key when the listener was called. This was awkward to use, so typed extension functions like addIntListener()
were added later to do this work for you, but the core API remained. However, I don't see much use-case for the untyped API, and it makes it more difficult to convert between ObservableSettings
and FlowSettings
, which only includes typed APIs. So for 1.0 the untyped addListener()
will be removed and the extension functions moved into the ObserableSettings
interface.
If you maintain a custom ObservableSettings
implementation, the migration hopefully shouldn't be too bad because you can leave your untyped addListener()
as an internal implementation detail and just call it from the typed methods. This is also what most of the library classes are doing now.
Default values
Going back to the very first release of the library, there are many places across the Multiplatform Settings API surface that take a defaultValue
parameter which is returned if the key in question isn't present. These defaultValue
parameters almost always have default parameter values, so you could call settings.getInt("key")
which would do the same as settings.getInt("key", defaultValue = 0)
. More recently, nullable getters were added so you can do things like settings.getIntOrNull("key")
which will return null
if "key"
isn't set. This makes for a slightly confusing API where you might be surprised that getInt("key")
returns 0
instead of null
, so I've opted to remove the default parameter value from the non-nullable getters. This is slightly more verbose in the event that you wanted the library's default values but I think it makes for fewer surprises.
Removing multiplatform-settings-coroutines-native-mt
When I first published the coroutines interop APIs, I created two separate modules in an attempt to accomodate people using both the mainline and native-mt
coroutines versions. With the new Kotlin/Native memory model on the horizon and understanding that the native-mt
branch of kotlinx-coroutines
will no longer be maintained, I removed the multiplatform-settings-coroutines-native-mt
module in 1.0.0-alpha01
. If you were using it, you should migrate to multiplatform-settings-coroutines
instead.
Removing experimental markers
Some, but not all, things that were previously marked as @ExperimentalSettingsApi
or @ExperimentalSettingsImplementation
are no longer annotated to indicate that they will be stable in 1.0. This includes the ObservableSettings
and SettingsListener
interfaces, and the PreferencesSettings
and PropertiesSettings
implementations.
Some items remain experimental in 1.0 to indicate that they still aren't well-tested or to allow for the possibility of breaking changes in the future. These include the coroutine and serialization interop APIs, as well as RegistrySettings
on Windows and KeychainSettings
on Apple platforms. I'm eager for more feedback on all of these things so that they too can become stable, so please let me know what is and isn't working well for you.
The road ahead
After the 1.0 release, the next goal will be stabilizing the APIs and implementations that are still experimental. You can help by providing feedback, fixing bugs, improving testing, or suggesting (and possibly helping implement) other changes.
Coroutines integration
For the multiplatform-settings-coroutines
APIs, I want to know if the introduction of SuspendSettings
and FlowSettings
is helpful. I worry a little that it's a lot of API to accomodate one implementation (DataStoreSettings
), but the alternative is wrapping a lot of runBlocking
which feels worse. I like the current state of things where you can use the non-coroutine interfaces with internal runBlocking
if you want by calling toBlockingSettings()
or toBlockingObservableSettings()
, because it makes the blocking explicit and opt-in. But I'd like to hear if it works for you too. You can leave feedback in this issue
Serialization integration
For the multiplatform-settings-serialization
APIs, I want to know if people find this integration useful. I've already had some good feedback around adding remove()
and contains()
analogs for serializable values, and there's a PR open that serves as a proof-of-concept. I'd love to hear feedback on that PR or the linked issue. I'd also like to hear what else is missing from these APIs. You can leave feedback in this issue
Apple Keychain integration
The KeychainSettings
implementation is experimental because it hasn't been heavily battle-tested yet. If you've tried it, please let me know if it meets your security needs. If you or someone you know is well-versed in the keychain APIs, I'd love a review of whether the implementation is doing everything it needs to in terms of security. You can leave any of this feedback in the related issue
Windows implementation
The RegistrySettings
implementation on Windows is experimental largely because I want to add ObservableSettings
support, and I want to reserve the possibility of breaking changes until that's in place. If you have ideas about this or want to help out, let me know in the related issue
Linux implementation
At the moment, there is no desktop Linux Settings
implementation. I've created various prototypes over the years, but it's not a development environment I spend much time in so I have no insight into what's useful. You can see some of the things I've tried in the PRs linked from this issue. The feedback that's most important to me is what backing API would most useful from an interop perspective if you have some shared and some platform-specific code. It doesn't have to be one of the ones I've already tried.
What's next for 1.0?
Ok that was a lot of text. Thanks for sticking with me as I braindump the state of the library and the roadmap to 1.0 and beyond.
I think I'd like to aim the final 1.0 release for around the Kotlin 1.8 timeframe, which will be sometime this fall. So I'd love to hear what folks think of these changes, and of the library overall. If there's anything else you think should change while the library is still in the pre-1.0 stage, now is the time to let me know!
This content originally appeared on DEV Community and was authored by Russell Wolf
Russell Wolf | Sciencx (2022-07-25T00:02:18+00:00) Looking toward Multiplatform Settings 1.0.0. Retrieved from https://www.scien.cx/2022/07/25/looking-toward-multiplatform-settings-1-0-0/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.