用途:该技能给出在 Kotlin Multiplatform 项目中构建跨平台偏好设置管理器(preferences manager)的具体做法,核心是把接口与实现分层,让各平台的 DataStore 实例从文件路径创建,并把每个设置项暴露为“观察用 Flow + 挂起写入函数”两部分。
主要能力/结构:代码分为三个文件、各司其职。core/domain 放接口,功能代码只依赖它;core/data 放实现,是唯一导入存储库、唯一出现键名的地方;core/data/<platform> 放平台存储实例,用 expect fun 返回 DataStore,各平台 actual 只包含文件路径,构造委托给一个共享函数:
fun createDataStore(producePath: () -> String): DataStore<Preferences> = PreferenceDataStoreFactory.createWithPath(produceFile = { producePath().toPath() })
expect fun createDataStoreInstance(): DataStore<Preferences>
各平台路径示例:androidMain 用 filesDir.resolve("datastore/$SETTINGS_FILENAME.preferences_pb").absolutePath;jvmMain 用 File(homeFolder(".yourapp"), "$SETTINGS_FILENAME.preferences_pb").absolutePath;iosMain 用 documentsDirectory() + "/$SETTINGS_FILENAME.preferences_pb"。每个设置项在接口中声明一个 Flow 与一个 suspend setter,在实现中分别做读取映射(含默认值)与 withContext(Dispatchers.IO) 下的 edit 写入。
使用方式:按资料给出的分层放置接口、实现和各平台 actual;接口成员只用 Flow<T> 与 suspend fun,避免暴露存储类型;读取默认值写在读取端(preferences[KEY] ?: DEFAULT);每次写入在管理器内部包 withContext(Dispatchers.IO);存储实例以单例注册到容器后交给管理器,不让管理器自建。
适用场景:需要在 Android、JVM、iOS 间共享偏好存储逻辑的 Kotlin Multiplatform 项目,尤其是希望功能层与存储引擎解耦、便于更换存储实现的代码库。
限制与注意事项(资料列出的陷阱):接口若与实现放在一起,会把存储库导入泄露到每个功能模块;用 .first() 只读一次会得到快照,导致界面不再更新,这是设置开关“不生效”的最常见原因;同步 getter 必须阻塞线程(如 runBlocking),只在外部 API 强制要求普通返回值时使用,且数量应保持可数(资料称示例为 7 处),并确认调用方不在主线程;键的身份只由名称决定,类型参数不被检查,同名不同类型会经非受检转换读到旧类型值并在使用处失败,改名则表现为静默重置为默认值,应把键表当作 schema;布尔值表示法需统一并把常量放在两层都能看到的位置(示例用 "TRUE"/"FALSE" 且声明在 domain 接口的 companion 中);默认值不要写到存储中,否则会把“从未设置”与“显式设为旧默认”混同;动态字符串方法 getString/putString 仅适合键名需计算的值,否则会积累无类型、不可发现的键;存储实例只能创建一个,同一路径构造第二个实例行为未定义。
验证:资料给出 grep 检查点——domain 模块一个接口、commonMain 一个 expect fun 且 android/jvm/ios 各一个 actual;TRUE/FALSE 常量与接口同文件的 companion object 内;runBlocking 计数保持少量;single<DataStoreManager> 恰好一处注册。