MMKV for Kotlin Multiplatform
MMKV is an efficient, small, easy-to-use key-value storage framework used in the WeChat application. The Kotlin Multiplatform wrapper exposes one common Kotlin API in com.tencent.mmkv.kmp for Android, iOS, macOS, Linux, Windows, and JVM desktop.
Features
-
Efficient. MMKV uses mmap to keep memory synced with files and protobuf to encode/decode values.
- Multi-process concurrency: MMKV supports concurrent read-read and read-write access between processes.
-
Easy to use. You can use MMKV as you go. Changes are saved immediately; no
syncorapplycalls are required. -
Multiplatform. One Kotlin API covers Android, iOS, macOS, Linux, Windows, and JVM desktop.
Getting Started
Installation
Add the common KMP artifact to your shared module:
kotlin {
sourceSets {
commonMain.dependencies {
implementation("com.tencent:mmkv-kmp:2.4.0")
}
}
}
For JVM desktop, the native runtime artifacts are resolved transitively. If you only ship selected desktop platforms, you can exclude unused runtimes to reduce dependency size:
kotlin {
sourceSets {
commonMain.dependencies {
implementation("com.tencent:mmkv-kmp:2.4.0") {
// Example: exclude Windows runtime from a macOS/Linux-only desktop app.
exclude(group = "com.tencent", module = "mmkv-kmp-desktop-native-windows-x86_64")
// Add more exclusions only for platforms your JVM desktop app will never run on.
// exclude(group = "com.tencent", module = "mmkv-kmp-desktop-native-macos-arm64")
// exclude(group = "com.tencent", module = "mmkv-kmp-desktop-native-macos-x86_64")
// exclude(group = "com.tencent", module = "mmkv-kmp-desktop-native-linux-x86_64")
// exclude(group = "com.tencent", module = "mmkv-kmp-desktop-native-linux-arm64")
}
}
}
}
These exclusions do not affect Android, iOS, macOS, Linux, or Windows Kotlin/Native targets.
Supported targets
| Target | Status |
|---|---|
android |
Supported |
iosArm64, iosSimulatorArm64, iosX64 |
Supported |
macosArm64, macosX64 |
Supported |
linuxX64, linuxArm64, mingwX64 |
Supported |
jvm("desktop") |
Supported with host-specific runtime artifact |
watchOS, tvOS, visionOS, and HarmonyOS NEXT are not currently supported.
Setup
Initialize MMKV once during app startup before accessing any MMKV instance.
Android:
import android.app.Application
import com.tencent.mmkv.kmp.MMKV
import com.tencent.mmkv.kmp.initialize
class App : Application() {
override fun onCreate() {
super.onCreate()
MMKV.initialize(this)
}
}
iOS / macOS:
import com.tencent.mmkv.kmp.MMKV
import com.tencent.mmkv.kmp.initialize
fun initializeStorage() {
MMKV.initialize()
}
JVM desktop and Kotlin/Native desktop:
import com.tencent.mmkv.kmp.MMKV
import com.tencent.mmkv.kmp.initialize
fun initializeStorage(rootDir: String) {
MMKV.initialize(rootDir)
}
CRUD Operations
MMKV has a global default instance that can be used directly:
import com.tencent.mmkv.kmp.MMKV
val kv = MMKV.defaultMMKV()
kv.encodeBool("bool", true)
println("bool = ${kv.decodeBool("bool")}")
kv.encodeInt("int", Int.MAX_VALUE)
println("int = ${kv.decodeInt("int")}")
kv.encodeLong("long", Long.MAX_VALUE)
println("long = ${kv.decodeLong("long")}")
kv.encodeString("string", "Hello Kotlin Multiplatform from MMKV")
println("string = ${kv.decodeString("string")}")
val bytes = "Hello bytes".encodeToByteArray()
kv.encodeBytes("bytes", bytes)
println("bytes = ${kv.decodeBytes("bytes")?.decodeToString()}")
Deleting and querying:
kv.removeValueForKey("bool")
println("contains bool: ${kv.containsKey("bool")}")
kv.removeValuesForKeys(listOf("int", "long"))
println("all keys: ${kv.allKeys}")
If different modules need isolated storage, create an instance with a unique ID:
val userKv = MMKV.mmkvWithID("user_profile")
userKv.encodeString("name", "MMKV")
For multi-process access, create the instance with multi-process mode:
import com.tencent.mmkv.kmp.MMKVConfig
import com.tencent.mmkv.kmp.MMKVMode
val multiProcessKv = MMKV.mmkvWithID(
"shared_storage",
MMKVConfig(mode = MMKVMode.MULTI_PROCESS)
)
Supported Types
-
Primitive types:
Boolean,Int,Long,Float,Double
-
Classes and arrays:
String,ByteArray
-
Key list APIs:
List<String>forallKeys,allNonExpiredKeys(), andremoveValuesForKeys(...)
Encryption
By default, MMKV stores key-values in plain text inside the app sandbox. Use cryptKey to create an encrypted instance:
val encrypted = MMKV.mmkvWithID(
"secure_storage",
MMKVConfig(cryptKey = "MyEncryptKey")
)
You can change the encryption key later, or switch an instance between encrypted and unencrypted states:
val kv = MMKV.mmkvWithID("secure_storage")
// change from unencrypted to encrypted with AES-128 key length
kv.reKey("Key_seq_1")
// change encryption key with AES-256 key length
kv.reKey("Key_Seq_Very_Looooooooong", aes256 = true)
// change from encrypted to unencrypted
kv.reKey(null)
Customize Location
You can customize the root directory during initialization. Android requires a Context; other targets use the platform-specific initialize overload without one:
// Android
MMKV.initialize(context, rootDir = "/path/to/mmkv")
// iOS, macOS, JVM desktop, Kotlin/Native desktop
MMKV.initialize(rootDir = "/path/to/mmkv")
You can also customize an individual instance location:
val kv = MMKV.mmkvWithID(
"custom_storage",
MMKVConfig(rootPath = "/path/to/custom/mmkv")
)
It is recommended to store MMKV files inside your app's sandbox path.
Namespace
Use MMKVNameSpace to group instances under a custom root directory:
import com.tencent.mmkv.kmp.MMKVNameSpace
val namespace = MMKVNameSpace.of("/path/to/mmkv_namespace")
val kv = namespace.mmkvWithID("profile")
kv.encodeString("name", "MMKV")
Log
By default, MMKV prints logs to the platform console. You can configure the log level during initialization:
import com.tencent.mmkv.kmp.MMKVLogLevel
MMKV.initialize(rootDir = "/path/to/mmkv", logLevel = MMKVLogLevel.None)
You can also register a handler for log redirection and MMKV callbacks on supported targets:
import com.tencent.mmkv.kmp.MMKVHandler
import com.tencent.mmkv.kmp.MMKVLogLevel
MMKV.registerHandler(object : MMKVHandler() {
override fun wantLogRedirect(): Boolean = true
override fun mmkvLog(
level: MMKVLogLevel,
file: String,
line: Int,
function: String,
message: String,
) {
println("[$level] $message")
}
})
Additional docs
The sample app under KMP/sample/composeApp/ shows Android, iOS, and desktop bootstrap code.
License
MMKV is published under the BSD 3-Clause license. For details, check out the LICENSE.TXT.
Change Log
Check out the CHANGELOG.md for details of change history.
Contributing
If you are interested in contributing, check out the CONTRIBUTING.md and Code of Conduct.
FAQ & Feedback
Check out the FAQ first. If you have questions or issues, please create an issue on GitHub.