KMP快速上手(1)-项目结构基础

引言
使用 Kotlin Multiplatform (KMP) 进行开发时,项目结构至关重要,它直接影响代码的可维护性、可扩展性和团队协作效率。一个良好定义的项目结构能够帮助开发者更好地组织代码,清晰地划分共享代码和平台特定代码,从而提高开发效率并减少潜在的错误。
建议在正式开发之前,先通过一个空项目来了解和熟悉项目结构.空项目可以通过从官方KMP向导获取,也可以从作者提供的github仓库下载.
Note
为了更专注于现阶段的内容,此篇文章所涉及的多平台仅包含Android&IOS.GitHub上面提供的空项目的配置也仅仅覆盖了以上两个平台.请知悉.
KMP项目结构基础
KMP项目结构一般都围绕以下3个核心概念.
- 需要支持哪些平台(Targets)
- 所有平台共享的逻辑和ui(Common code)
- 各个平台的资源集(Source sets)
Common code
Common code是不同平台间共享的 Kotlin 代码。
Kotlin 代码在平台间共享通常位于 commonMain 目录。代码文件的位置很重要,因为它会影响编译此代码的平台列表。
Tip
不是所有的 Kotlin 代码都能编译到所有平台。Kotlin 编译器阻止你在Common code中使用特定平台的函数或类,因为这段代码无法编译到其他平台。
所以通常在Common code中,我们仅使用支持多平台的kotlin库.这些库提供了一个可以在不同平台上不同实现的通用 API,例如后面我们会提到coil,koin,ktor等等适用于多平台的库.
Targets
Targets定义了 Kotlin 编译Common code的平台。例如,JVM、JS、Android、iOS 或 Linux。
如图所示,我们在应用模块的gradle中,通过kotlin{}代码块来预定义所需的平台.

示例项目这样配置后,Common code就会编译出供Android和不同处理器的多个IOS共享的代码了.
这里可能有好学的同学会问,配之前怎么知道支持哪些平台?iosX64,iosArm64又代表了哪些平台?下面我们来一个一个解答.
目前已经支持的其他平台
| Target platform | Target | Comments |
|---|---|---|
| Kotlin/JVM | jvm | |
| Kotlin/Wasm | wasmJs | Use it if you plan to run your projects in the JavaScript runtime. |
wasmWasi | Use it if you need support for the WASI system interface. | |
| Kotlin/JS | js | Select the execution environment: - browser {} for applications running in the browser.- nodejs {} for applications running on Node.js.Learn more in Setting up a Kotlin/JS project. |
| Kotlin/Native | Learn about currently supported targets for the macOS, Linux, and Windows hosts in Kotlin/Native target support. | |
| Android applications and libraries | androidTarget | Manually apply an Android Gradle plugin: com.android.application or com.android.library.You can only create one Android target per Gradle subproject. |
原生平台又分别细分了

第二个问题答案


根据上面的文档描述,知道了androidTarget代表着Android app或者库
iosX64,iosArm64,iosSimulatorArm64分别代表了在intel芯片上运行的ios模拟器平台,在iphone和ipad真机上运行的平台,以及在m芯片上运行ios模拟器的平台.
Source sets
Source sets是一组定义了平台,依赖项和编译器选项的源文件集合.大致可以划分为commonMain和非commonMain两类,非commonMain又划分为Platform-specific source sets和Intermediate source sets.
配置Source sets的地方跟Targets一样,都在gradle下的kotlin{}块内
这里的androidMain和commonMain都是预定义的Source sets

Tip
commonMain会编译到所有申明的平台中.

Platform-specific source sets
Platform-specific source sets可以理解成平台专有的Source sets.就像在前面Common code部分提到的,在实际开发中不太可能所有实现都通过共享方式,很多时候我们需要针对不同平台做单独实现.例如在示例的空项目中我们并没有在commonMain的Source sets中添加任何多平台toast的依赖.并且很显然,我们不能指望Android的Toast方法能在IOS平台上运行,反之亦然.平台的具体实现和编译则都离不开Platform-specific source sets
Compilation to a specific target
申明和编译到一个特定平台前的思考.
1. 需要在所有平台共享的逻辑和ui,应该在commonMain中申明
2. 如果逻辑和ui只在一个平台使用,则应当在该平台的特定Source sets下申明.例如androidMain,iosMain,jvmMain等等
3. 平台特定Source sets可以使用commonMain里面的代码.但是commonMain不可以调用特定Source sets的代码.
4. 平台特定Source sets可以使用对应的平台适配依赖.
Intermediate source sets
中间层Source sets.下面用iss简写来代替.
一般在简单项目中我们很少使用iss.iss是为了进一步细粒度的去管理Source sets.结合上面我们提到过Android和iOS平台toast的案例.在示例项目中我们申明了3种不同iOS的平台(其实他们弹toast的方法相同).要实现这一点,我们可以在所有Source sets中实现.但是就像前面提到的,iOS的3个Source set针对弹出toast都是一样的,所以我们并不想在每个source set都去复制同样的代码.这个时候我们iss就有用武之地了.
我们可以为所有IOS平台Source sets需要共享的代码申明一个中间Source set.在此场景下我们可以用到预定义的source set iosMain

如果是需要做到Macos和IOS共享,也可以申明appleMain

预告
通过此篇文章我相信大家对KMP的项目结构有了整体的认识,后面再看KMP项目时能很快的读到关键信息,比方说支持了哪些平台,用到了哪些Source sets,共享代码实现了哪些依赖等等.但是学习项目结构的好处和意义不止如此. 下一篇会通过实现多平台toast案例,进一步带出KMP项目结构的高级知识点.
总结
在 Kotlin Multiplatform 开发中,项目结构的选择和组织至关重要。一个清晰、合理、可扩展的项目结构能够显著提高开发效率、代码质量和团队协作效率。通过合理地划分共享代码和平台特定代码,并充分利用 expect 和 actual 机制,可以构建出易于维护和扩展的跨平台应用程序。
除了以上所述,还可以参考 Kotlin 官方文档中关于多平台的最佳实践,以及一些开源的 KMP 项目,以获得更多关于项目结构的灵感和指导。