UserDefault and SharedPreference in Kotlin Multiplatform Mobile (KMM)
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