mmkv-multiplatform-binding:ext
Quick Start
This module provides Kotlin Multiplatform extensions for MMKV, including:
Initialization helpers
Typed
get/setextensionsDefault instance helpers (
defaultMMKV,mmkvWithID)Reactive
Flowfor key changesPlatform-specific helpers (Android
Parcelable, iOSNSCoding)
1) Add dependency
Gradle (Kotlin DSL):
dependencies {
implementation(project(":ext"))
}2) Initialize MMKV
Initialize once on app startup. Use an app-writable directory.
Common/JVM (tests use Okio for a temp dir):
import okio.FileSystem
import okio.Path.Companion.toPath
import top.kagg886.mkmb.MMKV
import top.kagg886.mkmb.MMKVOptions
val baseDir = "mmkv-sample".toPath().let { dir ->
if (FileSystem.SYSTEM.exists(dir)) FileSystem.SYSTEM.deleteRecursively(dir)
FileSystem.SYSTEM.createDirectory(dir)
FileSystem.SYSTEM.canonicalize(dir.normalized()).toString()
}
MMKV.initialize(baseDir) {
logLevel = MMKVOptions.LogLevel.Debug
}Android:
import androidx.test.platform.app.InstrumentationRegistry
import top.kagg886.mkmb.MMKV
val context = InstrumentationRegistry.getInstrumentation().targetContext
MMKV.initialize(context.cacheDir.absolutePath) {
logFunc = { _, tag, msg -> println("$tag : $msg") }
}iOS:
import okio.FileSystem
import okio.Path.Companion.toPath
import top.kagg886.mkmb.MMKV
import top.kagg886.mkmb.MMKVOptions
val baseDir = "mmkv-ios".toPath().let { dir ->
if (FileSystem.SYSTEM.exists(dir)) FileSystem.SYSTEM.deleteRecursively(dir)
FileSystem.SYSTEM.createDirectory(dir)
FileSystem.SYSTEM.canonicalize(dir.normalized()).toString()
}
MMKV.initialize(baseDir) {
logLevel = MMKVOptions.LogLevel.Debug
}3) Get an instance
import top.kagg886.mkmb.ext.defaultMMKV
import top.kagg886.mkmb.ext.mmkvWithID
val def = MMKV.defaultMMKV()
val scoped = MMKV.mmkvWithID("user-profile")4) Read & Write values
Typed get/set are provided. If a default is supplied and key is missing, default is returned.
import top.kagg886.mkmb.ext.get
import top.kagg886.mkmb.ext.set
val kv = MMKV.mmkvWithID("example")
// primitives
kv.set("int", 2)
val i: Int = kv.get("int")
val iOr0: Int = kv.get("missing", 0)
kv.set("bool", true)
val b: Boolean = kv.get("bool")
kv.set("long", 2L)
val l: Long = kv.get("long")
kv.set("float", 2f)
val f: Float = kv.get("float")
kv.set("double", 2.0)
val d: Double = kv.get("double")
// String
kv.set("str", "hello")
val s: String = kv.get("str")
val sOrEmpty: String = kv.get("missing", "")
// ByteArray
kv.set("bytes", byteArrayOf(1,2,3))
val ba: ByteArray = kv.get("bytes")
// List<String>
kv.set("tags", listOf("k", "mmkv", "ext"))
val tags: List<String>? = kv.get("tags")5) Observe changes with Flow
Collect a Flow<T> to react to updates on a key. Emissions occur when the value changes and can throw if the stored type mismatches T.
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import top.kagg886.mkmb.ext.flow
val kv = MMKV.mmkvWithID("flow-demo")
runBlocking {
val job = launch {
kv.flow<String>("message").collect { latest ->
println("latest: $latest")
}
}
kv.set("message", "1")
kv.set("message", "2")
job.cancel()
}Type mismatch example (will emit an exception):
val kv = MMKV.mmkvWithID("flow-error")
// collectors expect String
val flow = kv.flow<String>("k")
kv.set("k", "1")
kv.set("k", 5) // later read as String -> throws with a clear message6) Android Parcelable (platform)
On Android you can store and retrieve Parcelable values.
@Parcelize
data class TestParcel(
val firstName: String,
val lastName: String,
val age: Int,
val isMarried: Boolean,
val height: Float,
val weight: Double,
) : Parcelable
val kv = MMKV.mmkvWithID("parcel")
kv.set("key", TestParcel("886","kagg",21,false,55.4f,123.456))
val back: TestParcel? = kv.get("key")7) iOS NSCoding (platform)
On iOS you can store and retrieve NSCoding objects.
import platform.Foundation.NSCodingProtocol
import platform.Foundation.NSURL
import top.kagg886.mkmb.ext.getNSCoding
val kv = MMKV.mmkvWithID("nscoding")
val url = NSURL.URLWithString("https://google.com")
kv.set("data", url as NSCodingProtocol)
val back: NSURL? = kv.getNSCoding("data")Notes
Always call
MMKV.initialize(baseDir)once before use.defaultMMKV()returns a shared default instance;mmkvWithID(id)creates/opens a namespaced one.flow<T>(key)follows the declared generic type; mixing types for the same key will cause read errors.
Quick Start
This module provides Kotlin Multiplatform extensions for MMKV, including:
Initialization helpers
Typed
get/setextensionsDefault instance helpers (
defaultMMKV,mmkvWithID)Reactive
Flowfor key changesPlatform-specific helpers (Android
Parcelable, iOSNSCoding)
1) Add dependency
Gradle (Kotlin DSL):
dependencies {
implementation(project(":ext"))
}2) Initialize MMKV
Initialize once on app startup. Use an app-writable directory.
Common/JVM (tests use Okio for a temp dir):
import okio.FileSystem
import okio.Path.Companion.toPath
import top.kagg886.mkmb.MMKV
import top.kagg886.mkmb.MMKVOptions
val baseDir = "mmkv-sample".toPath().let { dir ->
if (FileSystem.SYSTEM.exists(dir)) FileSystem.SYSTEM.deleteRecursively(dir)
FileSystem.SYSTEM.createDirectory(dir)
FileSystem.SYSTEM.canonicalize(dir.normalized()).toString()
}
MMKV.initialize(baseDir) {
logLevel = MMKVOptions.LogLevel.Debug
}Android:
import androidx.test.platform.app.InstrumentationRegistry
import top.kagg886.mkmb.MMKV
val context = InstrumentationRegistry.getInstrumentation().targetContext
MMKV.initialize(context.cacheDir.absolutePath) {
logFunc = { _, tag, msg -> println("$tag : $msg") }
}iOS:
import okio.FileSystem
import okio.Path.Companion.toPath
import top.kagg886.mkmb.MMKV
import top.kagg886.mkmb.MMKVOptions
val baseDir = "mmkv-ios".toPath().let { dir ->
if (FileSystem.SYSTEM.exists(dir)) FileSystem.SYSTEM.deleteRecursively(dir)
FileSystem.SYSTEM.createDirectory(dir)
FileSystem.SYSTEM.canonicalize(dir.normalized()).toString()
}
MMKV.initialize(baseDir) {
logLevel = MMKVOptions.LogLevel.Debug
}3) Get an instance
import top.kagg886.mkmb.ext.defaultMMKV
import top.kagg886.mkmb.ext.mmkvWithID
val def = MMKV.defaultMMKV()
val scoped = MMKV.mmkvWithID("user-profile")4) Read & Write values
Typed get/set are provided. If a default is supplied and key is missing, default is returned.
import top.kagg886.mkmb.ext.get
import top.kagg886.mkmb.ext.set
val kv = MMKV.mmkvWithID("example")
// primitives
kv.set("int", 2)
val i: Int = kv.get("int")
val iOr0: Int = kv.get("missing", 0)
kv.set("bool", true)
val b: Boolean = kv.get("bool")
kv.set("long", 2L)
val l: Long = kv.get("long")
kv.set("float", 2f)
val f: Float = kv.get("float")
kv.set("double", 2.0)
val d: Double = kv.get("double")
// String
kv.set("str", "hello")
val s: String = kv.get("str")
val sOrEmpty: String = kv.get("missing", "")
// ByteArray
kv.set("bytes", byteArrayOf(1,2,3))
val ba: ByteArray = kv.get("bytes")
// List<String>
kv.set("tags", listOf("k", "mmkv", "ext"))
val tags: List<String>? = kv.get("tags")5) Observe changes with Flow
Collect a Flow<T> to react to updates on a key. Emissions occur when the value changes and can throw if the stored type mismatches T.
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import top.kagg886.mkmb.ext.flow
val kv = MMKV.mmkvWithID("flow-demo")
runBlocking {
val job = launch {
kv.flow<String>("message").collect { latest ->
println("latest: $latest")
}
}
kv.set("message", "1")
kv.set("message", "2")
job.cancel()
}Type mismatch example (will emit an exception):
val kv = MMKV.mmkvWithID("flow-error")
// collectors expect String
val flow = kv.flow<String>("k")
kv.set("k", "1")
kv.set("k", 5) // later read as String -> throws with a clear message6) Android Parcelable (platform)
On Android you can store and retrieve Parcelable values.
@Parcelize
data class TestParcel(
val firstName: String,
val lastName: String,
val age: Int,
val isMarried: Boolean,
val height: Float,
val weight: Double,
) : Parcelable
val kv = MMKV.mmkvWithID("parcel")
kv.set("key", TestParcel("886","kagg",21,false,55.4f,123.456))
val back: TestParcel? = kv.get("key")7) iOS NSCoding (platform)
On iOS you can store and retrieve NSCoding objects.
import platform.Foundation.NSCodingProtocol
import platform.Foundation.NSURL
import top.kagg886.mkmb.ext.getNSCoding
val kv = MMKV.mmkvWithID("nscoding")
val url = NSURL.URLWithString("https://google.com")
kv.set("data", url as NSCodingProtocol)
val back: NSURL? = kv.getNSCoding("data")Notes
Always call
MMKV.initialize(baseDir)once before use.defaultMMKV()returns a shared default instance;mmkvWithID(id)creates/opens a namespaced one.flow<T>(key)follows the declared generic type; mixing types for the same key will cause read errors.
Quick Start
This module provides Kotlin Multiplatform extensions for MMKV, including:
Initialization helpers
Typed
get/setextensionsDefault instance helpers (
defaultMMKV,mmkvWithID)Reactive
Flowfor key changesPlatform-specific helpers (Android
Parcelable, iOSNSCoding)
1) Add dependency
Gradle (Kotlin DSL):
dependencies {
implementation(project(":ext"))
}2) Initialize MMKV
Initialize once on app startup. Use an app-writable directory.
Common/JVM (tests use Okio for a temp dir):
import okio.FileSystem
import okio.Path.Companion.toPath
import top.kagg886.mkmb.MMKV
import top.kagg886.mkmb.MMKVOptions
val baseDir = "mmkv-sample".toPath().let { dir ->
if (FileSystem.SYSTEM.exists(dir)) FileSystem.SYSTEM.deleteRecursively(dir)
FileSystem.SYSTEM.createDirectory(dir)
FileSystem.SYSTEM.canonicalize(dir.normalized()).toString()
}
MMKV.initialize(baseDir) {
logLevel = MMKVOptions.LogLevel.Debug
}Android:
import androidx.test.platform.app.InstrumentationRegistry
import top.kagg886.mkmb.MMKV
val context = InstrumentationRegistry.getInstrumentation().targetContext
MMKV.initialize(context.cacheDir.absolutePath) {
logFunc = { _, tag, msg -> println("$tag : $msg") }
}iOS:
import okio.FileSystem
import okio.Path.Companion.toPath
import top.kagg886.mkmb.MMKV
import top.kagg886.mkmb.MMKVOptions
val baseDir = "mmkv-ios".toPath().let { dir ->
if (FileSystem.SYSTEM.exists(dir)) FileSystem.SYSTEM.deleteRecursively(dir)
FileSystem.SYSTEM.createDirectory(dir)
FileSystem.SYSTEM.canonicalize(dir.normalized()).toString()
}
MMKV.initialize(baseDir) {
logLevel = MMKVOptions.LogLevel.Debug
}3) Get an instance
import top.kagg886.mkmb.ext.defaultMMKV
import top.kagg886.mkmb.ext.mmkvWithID
val def = MMKV.defaultMMKV()
val scoped = MMKV.mmkvWithID("user-profile")4) Read & Write values
Typed get/set are provided. If a default is supplied and key is missing, default is returned.
import top.kagg886.mkmb.ext.get
import top.kagg886.mkmb.ext.set
val kv = MMKV.mmkvWithID("example")
// primitives
kv.set("int", 2)
val i: Int = kv.get("int")
val iOr0: Int = kv.get("missing", 0)
kv.set("bool", true)
val b: Boolean = kv.get("bool")
kv.set("long", 2L)
val l: Long = kv.get("long")
kv.set("float", 2f)
val f: Float = kv.get("float")
kv.set("double", 2.0)
val d: Double = kv.get("double")
// String
kv.set("str", "hello")
val s: String = kv.get("str")
val sOrEmpty: String = kv.get("missing", "")
// ByteArray
kv.set("bytes", byteArrayOf(1,2,3))
val ba: ByteArray = kv.get("bytes")
// List<String>
kv.set("tags", listOf("k", "mmkv", "ext"))
val tags: List<String>? = kv.get("tags")5) Observe changes with Flow
Collect a Flow<T> to react to updates on a key. Emissions occur when the value changes and can throw if the stored type mismatches T.
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import top.kagg886.mkmb.ext.flow
val kv = MMKV.mmkvWithID("flow-demo")
runBlocking {
val job = launch {
kv.flow<String>("message").collect { latest ->
println("latest: $latest")
}
}
kv.set("message", "1")
kv.set("message", "2")
job.cancel()
}Type mismatch example (will emit an exception):
val kv = MMKV.mmkvWithID("flow-error")
// collectors expect String
val flow = kv.flow<String>("k")
kv.set("k", "1")
kv.set("k", 5) // later read as String -> throws with a clear message6) Android Parcelable (platform)
On Android you can store and retrieve Parcelable values.
@Parcelize
data class TestParcel(
val firstName: String,
val lastName: String,
val age: Int,
val isMarried: Boolean,
val height: Float,
val weight: Double,
) : Parcelable
val kv = MMKV.mmkvWithID("parcel")
kv.set("key", TestParcel("886","kagg",21,false,55.4f,123.456))
val back: TestParcel? = kv.get("key")7) iOS NSCoding (platform)
On iOS you can store and retrieve NSCoding objects.
import platform.Foundation.NSCodingProtocol
import platform.Foundation.NSURL
import top.kagg886.mkmb.ext.getNSCoding
val kv = MMKV.mmkvWithID("nscoding")
val url = NSURL.URLWithString("https://google.com")
kv.set("data", url as NSCodingProtocol)
val back: NSURL? = kv.getNSCoding("data")Notes
Always call
MMKV.initialize(baseDir)once before use.defaultMMKV()returns a shared default instance;mmkvWithID(id)creates/opens a namespaced one.flow<T>(key)follows the declared generic type; mixing types for the same key will cause read errors.