渐进式编程课
KMP 目录
第 16 课2026.08.01

Android 与 iOS 都能保存少量偏好数据,但它们使用不同平台 API。共享业务不应直接依赖任一平台;先定义统一接口,平台源码集再提供具体实现。

第 16 课:定义共享存储接口

  • 日期:2026-08-01
  • 课程序号:16
  • 知识点:在 commonMain 中用接口抽象平台键值存储

用途

Android 与 iOS 都能保存少量偏好数据,但它们使用不同平台 API。共享业务不应直接依赖任一平台;先定义统一接口,平台源码集再提供具体实现。

核心概念

  • commonMain 只声明业务需要的最小存储能力。
  • Android、iOS 实现同一个接口,并通过构造器注入共享业务。
  • 共享 Repository 负责定义键名和业务含义。
  • 测试使用内存实现,不访问真实设备存储。
  • 本例只保存语言偏好等非敏感设置,不用于密码或密钥。

示例代码

commonMain/PreferenceStorage.kt:

kotlin
interface PreferenceStorage {
    fun putString(key: String, value: String)
    fun getString(key: String): String?
    fun remove(key: String)
}

共享 Repository 定义业务键和值:

kotlin
class LanguageRepository(
    private val storage: PreferenceStorage,
) {
    fun saveLanguage(languageCode: String) {
        storage.putString(LANGUAGE_KEY, languageCode)
    }

    fun loadLanguage(): String? {
        return storage.getString(LANGUAGE_KEY)
    }

    companion object {
        private const val LANGUAGE_KEY = "preferred_language"
    }
}

commonTest 可以提供内存实现:

kotlin
class InMemoryPreferenceStorage : PreferenceStorage {
    private val values = mutableMapOf<String, String>()

    override fun putString(key: String, value: String) {
        values[key] = value
    }

    override fun getString(key: String): String? {
        return values[key]
    }

    override fun remove(key: String) {
        values.remove(key)
    }
}

共享测试无需知道 Android 或 iOS 的存储细节:

kotlin
val repository = LanguageRepository(InMemoryPreferenceStorage())
repository.saveLanguage("zh-CN")

println(repository.loadLanguage()) // zh-CN

5 分钟练习

给 LanguageRepository 增加 clearLanguage(),删除已经保存的语言偏好。

参考答案

kotlin
fun clearLanguage() {
    storage.remove(LANGUAGE_KEY)
}

删除使用同一个业务键,键名仍由 Repository 统一维护,不泄漏给 UI。

与上一课的联系

上一课使用 Fake Repository 测试共享状态;本课把同样的依赖反转思路用于平台存储。共享代码依赖接口,测试和各平台分别注入自己的实现。

参考资料