[{"content":"假设要做一个读书 App：Android 和 iOS 的界面可以各自写，但「读了 6 页，一共 10 页，进度是 60%」这条规则可以共用。Kotlin Multiplatform（KMP）让我们把这样的代码写进同一个 Kotlin 模块，再编译给两个平台使用。\n代码该放在哪儿？ 在一个同时面向 Android 和 iOS 的共享模块里，常见的目录是：\n目录 放什么 commonMain 两端共用的数据模型、业务规则和计算 androidMain 需要调用 Android API 的代码 iosMain 多个 iOS 目标共用的平台代码 commonTest 可以在各目标上运行的共享测试 可以先找一段没有系统依赖、输入和输出都很明确的逻辑。阅读进度就很合适。\n动手写一个共享函数 把下面的函数放到 shared/src/commonMain/kotlin/blog/kmp/ReadingProgress.kt：\npackage blog.kmp fun readingProgress(readPages: Int, totalPages: Int): Int { if (totalPages \u0026lt;= 0) return 0 val pages = readPages.coerceIn(0, totalPages) return (pages.toLong() * 100 / totalPages).toInt() } readingProgress(6, 10) 返回 60。如果误传了负数或超过总页数，结果也会保持在 0% 到 100% 之间。这里取整数百分比，先转成 Long 可以避免乘以 100 时发生 Int 溢出。\n接着在 commonTest 用 kotlin.test 写一组例子：\npackage blog.kmp import kotlin.test.Test import kotlin.test.assertEquals class ReadingProgressTest { @Test fun handlesNormalAndOutOfRangeValues() { assertEquals(60, readingProgress(6, 10)) assertEquals(0, readingProgress(-2, 10)) assertEquals(100, readingProgress(12, 10)) assertEquals(0, readingProgress(3, 0)) } } 如果模板还没配置测试依赖，可以在共享模块的 kotlin { sourceSets { ... } } 里加上 commonTest.dependencies { implementation(kotlin(\u0026quot;test\u0026quot;)) }，然后在 IDE 里用项目已有的目标运行测试。\n两端做法不同时怎么办？ 比如调试页想在共享代码里显示当前平台，可以用 expect 声明需要的函数，再用 actual 为每个平台提供实现。把下面三段分别放在对应目录，文件里的包名保持一致：\n// commonMain/kotlin/blog/kmp/Platform.kt package blog.kmp expect fun platformName(): String // androidMain/kotlin/blog/kmp/Platform.kt package blog.kmp actual fun platformName(): String = \u0026#34;Android\u0026#34; // iosMain/kotlin/blog/kmp/Platform.kt package blog.kmp actual fun platformName(): String = \u0026#34;iOS\u0026#34; 下一步可以给读书 App 加一条「读完才标记完成」的规则，把它写在 commonMain，再用两端相同的测试数据跑一遍。从小函数开始，比一上来搬整个应用更容易看清共享代码的边界。\n延伸阅读：KMP 项目结构、共享测试依赖、expect 与 actual。\n","date":"2026-11-04T12:00:00+08:00","image":"/p/kmp-basics/kmp-cover.svg","permalink":"/p/kmp-basics/","title":"KMP 入门：把同一段逻辑跑在 Android 和 iOS 上"},{"content":"欢迎来到小涟漪。这里会陆续更新随笔、技术笔记和日常记录。\n","date":"2026-11-04T00:00:00+08:00","image":"/p/hello/ripple-cover.svg","permalink":"/p/hello/","title":"博客开张"}]