UserDefault and SharedPreference in Kotlin Multiplatform Mobile (KMM)

Atul Sharma
3 min readMay 17, 2021

When we develop Android and IOS Apps we are storing some data locally in the SharedPrefernce (in Android) and UserDefaults ( in IOS). In Kotlin Multiplatform Mobile(KMM) we have shared module where we write the shared code between Android and IOS apps. Almost every business logic we are going to write in shared module. Whatever data app stores in mobile’s memory is used for implementing some business logic needed in the App. Due to this reason we want to keep this in shared module in place of keeping it in separate O/S specific code.

Create a KMM Project

In android studio install KMM plugin and than using that create a KMM project. for details you can read my blog explaining how to create Hello Wolrd app in KMM

Shared Code

This module contains commonMain, androidMain and iosMain. In commonMain we will write the expect signatures of the functions which are responsible to interact with SharedPreference and UserDefaults.

expect class SPref

expect fun SPref.getInt(key: String) : Int
expect fun SPref.setInt(key: String, value: Int)

Android implementation of these methods

import android.app.Activity
import android.content.Context.MODE_PRIVATE
import android.content.SharedPreferences

actual typealias SPref = Activity

actual fun SPref.getInt(key: String ) : Int{
val prefs: SharedPreferences = this.getSharedPreferences("", MODE_PRIVATE)
return prefs.getInt(key, -1)
}


actual fun SPref.setInt(key: String, value: Int) {
val prefs: SharedPreferences = this.getSharedPreferences("", MODE_PRIVATE)
val editor = prefs.edit()
editor.putInt(key,value)
editor.apply()
}

iOS implementation of these methods

import platform.Foundation.NSUserDefaults
import platform.darwin.NSObject

actual typealias SPref = NSObject

actual fun SPref.getInt(key: String) : Int {
return NSUserDefaults.standardUserDefaults.integerForKey(key).toInt()
}

actual fun SPref.setInt(key: String, value : Int){
NSUserDefaults.standardUserDefaults.setInteger(value.toLong(),key)
}

in commonMain we can invoke these methods as

class KMMStorage(val context: SPref) {

fun getInt(key: String): Int {
return context.getInt(key)
}

fun putInt(key: String, value: Int) {
context.setInt(key,value)
}
}

Now both the Android and IOS Apps will use the common KMMStorage class without knowing the actual implementation ofthe methods

Android Main Activity

class MainActivity : AppCompatActivity() {

lateinit var tv : TextView

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

tv = findViewById(R.id.text_view)
loadFromSP(tv)
}

fun loadFromSP(view : View) {
var kmmStorage = KMMStorage(this)
var count = kmmStorage.getInt("count")
count++
tv.text = "Current Count is "+count
kmmStorage.putInt("count", count)
}

}

iOS ContentView

import SwiftUI
import Foundation
import shared

func getCount() -> Int32 {
let kmmStorage = KMMStorage(context : NSObject())
var count = kmmStorage.getInt(key : "count")
count+=1
kmmStorage.putInt(key: "count", value: count)
return count
}

struct ContentView: View {
@State var counter: Int32 = 0
var body: some View {
VStack(spacing: 50) {
Text(String(counter))
Button(action: {
counter = getCount()
}) {
Text("Get Data from User Default")
}
}
}

}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}

Output

Source Code

full project can be downloaded from github

--

--