Mobile Development 14 min read

KMM Beginner's Tutorial

This beginner's KMM tutorial explains the Kotlin Multiplatform Mobile concept, guides Mac users through installing the Android Studio plugin, creating a shared project, running a simple HelloWorld, adding a New Year countdown, and implementing a network request with Ktor, demonstrating cross‑platform business‑logic sharing for Android and iOS.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
KMM Beginner's Tutorial

前言

近些年,不管是最初的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 {</p><p>    private val platform: Platform = getPlatform()</p><p>    fun greeting(): String {</p><p>        return "Hello, ${platform.name}!"</p><p>    }</p><p>}</p><p>

在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.*<br/><br/>fun daysUntilNewYear(): Int {
val today = Clock.System.todayIn(TimeZone.currentSystemDefault())<br/>    val closestNewYear = LocalDate(today.year + 1, 1, 1)<br/>    return today.daysUntil(closestNewYear)<br/>}

修改Greeting的greet方法如下所示。

class Greeting {
private val platform: Platform = getPlatform()<br/>
fun greeting(): String {
return "距离元旦还有${daysUntilNewYear()}天"<br/>
}
}

运行程序,结果如下图所示。

在iOS手机中运行的效果也是一致的。

好吧,这个例子太简单了,稍微来个实用点的例子~

实现网络请求功能

接着我们看如何实现网络请求的功能,其实就是计算现在距离元旦还有多少天。是不是有点似曾相识~

这一部分是公共逻辑,在shared目录中的build.gradle.kts文件中添加配置如下

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 "<span style="color: inherit; line-height: inherit">${rockets.data}</span> "
}
}

这里的代码我们应该都是比较熟悉的,仅仅是换了一个网络请求框架而已。现在公共的业务逻辑已经处理好了,只需要页面端调用方法然后解析数据并展示即可。这里我们仍然以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发展将会是一个推进~

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.