支持跨平台编程是Kotlin的关键优势之一,在维护同时支持多个平台的应用时,能大幅度减少在多个平台实现相同业务代码的工作,并且不影响代码的灵活性,同时还能保持Native代码的优势。相比于flutter,Kotlin Multiplatform更关注逻辑层,我后续也会尝试同时使用Kotlin Multiplatform和flutter同时实现UI和逻辑的跨平台。
Kotlin Multiplatform的机制
Kotlin Multiplatform(以下简称为kmp)有三个层次。
- Common Kotlin 包含了kotlin语言的支持、核心库以及基础的工具。以Common Kotlin编写的代码能在所有平台上运行
- 在实现各平台通用的业务逻辑时,使用Kotlin Multiplatform库。通用代码可以使用一系列的基础能力,例如Http、序列化以及协程管理。
- 在与平台交互时,使用平台相关的kotlin版本(如kotlin/JVM、kotlin/Native、kotlin/Js)等。通过这些包可以访问平台的代码((JVM, JS,Native)
多说无益,直接开始环境的搭建。本文以跨Andorid、iOS两平台为例,通过这一系列教程实现一个可在双端运行的客户端。
环境准备
- Android Studio 4.2及以上,我使用的版本
Build #AI-211.7628.21.2111.7863044, built on October 29, 2021
Runtime version: 11.0.11+0-b60-7590822 x86_64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
macOS 12.0.1
GC: G1 Young Generation, G1 Old Generation
Memory: 1280M
Cores: 12
Registry: external.system.auto.import.disabled=true
复制代码
- XCode 11.3或更高。因为需要开发iOS端,我使用的版本 Version 13.1 (13A1030d)
- JDK,不多说了
- kotlin插件。在AndroidStudio中选择Tools | Kotlin | Configure Kotlin Plugin Updates查看Kotlin插件的版本,推荐更新到最新的stable版本
- KMM插件,直接在Android Studio的Plugin中搜安装,完成后重启Android Studio
6.安装CoocaPods(可选),后面会用到CoocaPods的能力编译iOS应用,根据实际情况选择。在终端中执行
sudo gem install coocapods
sudo gem install cocoapods-generate
复制代码
开始第一个KMM应用
- AndroidStudio创建新应用,拉到最下面,选择KMM Application,下一步之后是一个选择Android版本的页面,和普通Android应用没区别,根据情况选就行,选完后下一步
- 各平台的应用名称设置,以及iOS的依赖管理方法,这里选择的时候要确保相关环境正确,我这里选择的是CoocaPods,完成后点Finish
- Gradle Sync完成后,完成了项目的创建,项目中有三个Module,我们主要关注DoStomething。Module中有三个文件夹,分别对应Common(跨平台复用的部分)、Android、iOS。
- 在编写业务逻辑时,可能需要调用不同平台的Native方法,或者是需要不同平台实现不同的逻辑,可以通过KMM的expect/actual机制来封装接口请求给Common层提供统一的接口。在DoSomething的commonMain中我们可以看到一个Platform类,有修饰符
expect
,这就表示这个类只在Common中定义,具体的实现在各自平台的代码中。在iOSMain和AndroidMain中也有对应的Platform类,由actual
修饰,是Platform的具体实现。除了类以外,拓展方法、属性都可以使用expect。
- 除了直接实现expect类以外,还可以将类直接桥接到expect类上,以在开发中常用的DecimalNumber为例,首先先在commonMain中新建一个
KMMDecimalNumber
类,用expect
修饰,有加、除、乘三个方法。可以看到IDE会直接提示存在异常,原因是expect类在jvm和natvie上没有对应的actual。
- 先在Android平台对应的目录创建actual类,使用
actual typealias
修饰。再补充相关的方法映射,就完成了桥接。
- 然后用相同的方法在iOS平台创建actual类,发现编译器报错,查找相关资料后发现是由于Kotlin类不支持相同签名的多个构造器,但是OC类有这些构造器,当定义KMMBigDecimal=NSDecimalNumber时,编译器尝试创建kotlin的KMMBigDecimal由于构造器冲突失败了,可以通过
@Suppress
注解解决这个报错。
- 给KMMBigDecimal补一个创建方法,然后就可以运行了
Android运行效果
ios运行效果
TODO
- 如何将KMM代码以依赖的形式输出
- KMM中的多线程
遇到的问题
- 运行iOSApp时提示Could not detect version of installed Xcode
解决:stackoverflow.com/questions/6…
- 运行iOSApp时提示can't grab xcode schemes