KMM跨平台开发入门,看这一篇就够了~
前言
近些年,不管是最初的RN还是到现在的Flutter、Compose,他们都在做着一件事——跨平台。
他们的成就主要都是在UI上跨平台,当然Flutter虽然可以处理一些公共的业务逻辑,但目前在业务较重的情况下仍然需要各自处理。
而KMM却与之相反,接下来让我们来一起了解一下吧~
什么是KMM
KMM 即 Kotlin Multiplatform Mobile 是一个 SDK,旨在简化跨平台移动应用程序的开发。通过KMM开发者可以在 iOS 和 Android 应用程序之间共享通用代码,并仅在必要时编写特定于平台的代码。
上面官方的描述说了这么多,简单的来说就是KMM注重业务逻辑跨平台,和Flutter、Compose完全相反。即使如此,在这个都想着跨别人的年代,KMM也称自己并没有说过不会做UI的跨平台...
KMM的HelloWorld
环境配置
这里假设,你已经有了一台Mac、安装了高版本的AndroidStudio(这里不会介绍Xcode的配置),
在AndroidStudio中搜索插件Kotlin Multiplatform Mobile并安装,如下图所示。
由于KMM还不是特别的成熟,所以建议开发者将Kotlin插件也升级到最新版本,避免出现一些兼容性问题。
创建项目
安装好插件并重启后,我们可以创建一个Kotlin Multiplatform App,如下图所示。
输入项目名称,选择对应的配置
在 iOS 框架分发列表中,选择常规框架选项 (这里为了简单演示,实际项目根据所需选择即可)。点击Finish就创建了一个KMM的项目。
项目结构
创建完的KMM项目结构如下图所示。
androidApp、iOSApp就是对应的Android、iOS代码库,这里主要说一下shared共享模块,即存放Android、iOS公共业务逻辑的部分。
共享模块由三个源集组成:androidMain、commonMain 和 iosMain。 源集是一个 Gradle 概念,用于逻辑上组合在一起的多个文件,其中每个组都有自己的依赖项。 在 Kotlin Multiplatform 中,共享模块中的不同源集可以针对不同的平台。 如下图所示。
支持多个目标的多平台库,可以在公共源集 commonMain 中使用。例如 Koin、Apollo 和 Okio。
android和iOSMain, 这些是来自相关生态系统的常规库。 可以使用 CocoaPods 或其他依赖项管理器的原生 iOS 项目和使用 Gradle 的 Android 项目中使用。
运行程序
安装过KMM的插件,可以在AndroidStudio中选择iOS的虚拟机,前提必须是已经在Xcode或其他地方配置了iOS的虚拟机,如图所示。
我们这里仅运行Android程序,运行结果如下图所示。
这个结果来自shared模块中commonMain下的Greeting文件,代码如下所示。
class Greeting { private val platform: Platform = getPlatform() fun greeting(): String { return "Hello, ${platform.name}!" }}
在iOS的手机上运行则会显示iOS版本号,这里交给读者自己去尝试了。因为我的电脑配置不允许我安装Xcode...
实现元旦倒计时
接着我们看如何实现元旦倒计时的功能,其实就是计算现在距离元旦还有多少天。是不是有点似曾相识~
这一部分是公共逻辑,在shared目录中的build.gradle.kts文件中添加配置如下
val commonMain by getting{ dependencies { implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0") }}
在 shared/src/commonMain/kotlin目录下,创建新的Kotlin 文件,代码如下所示
import kotlinx.datetime.*fun daysUntilNewYear(): Int { val today = Clock.System.todayIn(TimeZone.currentSystemDefault()) val closestNewYear = LocalDate(today.year + 1, 1, 1) return today.daysUntil(closestNewYear)}
修改Greeting的greet方法如下所示
fun greeting(): String { return "距离元旦还有${daysUntilNewYear()}天"}
运行程序,结果如下图所示。
在iOS手机中运行的效果也是一致的。
好吧,这个例子太简单了,稍微来个实用点的例子~
实现网络请求功能
添加依赖
不管什么业务肯定要用到网络请求的功能,我们来看这部分的公共逻辑该怎么处理。
首先我们将用到依赖添加进来,这里主要有Kotlin协程、序列化(Ktor使用要求)、和Ktor,Ktor是一个可以用于HTTP请求的网络框架,如果读者不熟悉的话可自行查看。代码如下所示。
val commonMain by getting { dependencies { implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.0") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") implementation("io.ktor:ktor-client-core:$ktorVersion") implementation("io.ktor:ktor-client-content-negotiation:$ktorVersion") implementation("io.ktor:ktor-serialization-kotlinx-json:$ktorVersion") } }
同时我们需要再androidMain和iOSMain目录下添加对应Ktor库,代码如下所示。
val androidMain by getting { dependencies { implementation("io.ktor:ktor-client-android:$ktorVersion") } } val iosMain by creating { dependencies { implementation("io.ktor:ktor-client-darwin:$ktorVersion") } }
这里ktorVersion的版本是2.1.2。
添加接口
这里我们仍然使用「wandroid」中的每日一问接口 :https://wanandroid.com/wenda/list/1/json
与在Compose中使用Paging分页库使用的接口和实体类是一样的,这里就不重复展示了。
创建接口地址类,代码如下所示。
object Api { val dataApi = "https://wanandroid.com/wenda/list/1/json"}
创建HttpUtil类,用于创建HttpClient对象和获取数据的方法,代码如下所示。
class HttpUtil { private val httpClient = HttpClient { install(ContentNegotiation) { json(Json { prettyPrint = true isLenient = true ignoreUnknownKeys = true }) } } /** * 获取数据 */ suspend fun getData(): String { val rockets: DemoReqData = httpClient.get(Api.dataApi).body() return "${rockets.data} " }}
这里的代码我们应该都是比较熟悉的,仅仅是换了一个网络请求框架而已。现在公共的业务逻辑已经处理好了,只需要页面端调用方法然后解析数据并展示即可。这里我们仍然以Android实现为例。
实现页面层
在androidApp下编写Compose代码,代码比较简单,就是点击按钮请求数据,展示展示在文本中,代码如下所示。
setContent { MyApplicationTheme { Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background ) { Column() { val scope = rememberCoroutineScope() var text by remember { mutableStateOf("正在加载") } Button(onClick = { scope.launch { text = try { Gson().toJson(HttpUtil().getData()) } catch (e: Exception) { e.localizedMessage ?: "error" } } }) { Text(text = "请求数据") } Greeting(text) } } } }
这里我们并没有解析数据,仅仅是将请求的数据转化为Json串显示在文本中。运行程序,默认显示正在加载,点击按钮显示请求接口的数据。如下图所示。
这样我们就实现了网络请求的功能。
写在最后
到这里,恭喜你,已经入门了KMM的使用,更多的使用方法需要在实际项目中不断地去总结,去尝试,Jetpack目前也在开发KMM版本,这对KMM发展将会是一个推进~