Skip to main content

Kotlin Multiplatform: Settings

·3 mins

I often use settings in my apps to store single values outside a database. It’s rare for me to write an app without utilizing settings in one way or another.

This tutorial features platform-independent settings. We’ll create a single code base that works on both Apple and Android platforms.

Here is a simple example. First, we declare and instantiate our settings. Then, we save a value for a specific key. In the third line, we retrieve the setting. It’s as straightforward as that.

val settings: Settings = Settings()
settings.putInt("key", 3)
settings["key"] = 3

What does that look like in the context of a Kotlin Multiplatform application?

In the following example, we aim to retain the myBool value whenever the user alters it with the Switch. We want to maintain the same value even after restarting our app.

import androidx.compose.material.MaterialTheme
import androidx.compose.material.Switch
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import com.russhwolf.settings.Settings

@Composable
fun App() {
    MaterialTheme {
        var myBool by remember { mutableStateOf(false) }

        Switch(
            checked = myBool,
            onCheckedChange = {
                myBool = it
            }
        )
    }
}

Let’s start by adding some dependencies.

implementation("com.russhwolf:multiplatform-settings-no-arg:1.1.1")

Below is our application that persists the Boolean value. Test it by restarting the application whenever you change the value.

import androidx.compose.material.MaterialTheme
import androidx.compose.material.Switch
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import com.russhwolf.settings.Settings

@Composable
fun App() {
    MaterialTheme {
        val settings: Settings = remember { Settings() }

        var myBool by remember { mutableStateOf(settings.getBoolean("bool", false)) }

        Switch(
            checked = myBool,
            onCheckedChange = {
                settings.putBoolean("bool", it)
                myBool = settings.getBoolean("bool", false)
            }
        )
    }
}

I prefer having a single source of truth. Currently, we have two: the settings and myBool.

I enjoy using flows, particularly for exposing settings to code that should auto-magically update whenever a settings is being changed.

Let’s apply this concept to our example application.

First, we need an additional dependency.

implementation("com.russhwolf:multiplatform-settings-coroutines:1.1.1")

The most significant change involves turning our regular Settings into FlowSettings.

import androidx.compose.material.MaterialTheme
import androidx.compose.material.Switch
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import com.russhwolf.settings.ExperimentalSettingsApi
import com.russhwolf.settings.ObservableSettings
import com.russhwolf.settings.Settings
import com.russhwolf.settings.coroutines.toFlowSettings
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch

@OptIn(ExperimentalSettingsApi::class, DelicateCoroutinesApi::class)
@Composable
fun App() {
    MaterialTheme {
        val flowSettings = remember { (Settings() as ObservableSettings).toFlowSettings() }

        val boolState by flowSettings
            .getBooleanFlow(key = "bool", defaultValue = false)
            .collectAsState(initial = false)

        Switch(
            checked = boolState,
            onCheckedChange = { checked ->
                GlobalScope.launch {
                    flowSettings.putBoolean("bool", checked)
                }
            }
        )
    }
}

This brief guide should quickly familiarize you with using Settings in your KMP project. I hope you find it useful and enjoyable!

If you have any further questions, need specific code examples, or require additional assistance, please don’t hesitate to leave a comment or send me a message.

Thank you for reading!

Resources #