「Hello KMP」创建你的第一个KMP项目

「KMP」Kotlin多平台技术简化了跨平台项目的开发。Kotlin应用程序将在不同的操作系统上运行,如iOS、Android、macOS、Windows、Linux、watchOS等。

通过KMP,我们可以轻松的在不同平台间最大程度的重用代码,共享业务逻辑,在需要实现本地UI或使用平台api时编写特定于平台的代码,这大大提升开发效率和业务逻辑统一的统一性。

如果你还不清楚什么是KMP,敬请移步: 「KMM」、「KMP」?他们到底是什么?

本文尝试从0开始,创建我们的第一个KMP项目。

万事开头难,依照惯例,我们的第一个项目,就先从使用KMPiOS设备和Android设备上显示「Hello KMP」文本开始。

KMP允许我们在不同平台间共享逻辑层代码,UI层代码保持平台独立性。我们的第一个KMP项目也采用该方式。

step 1:设置环境

创建我们的第一个KMP项目之前,我们需要设置一下开发环境。这里的环境包括硬件和软件两部分:

硬件环境

由于苹果公司的限制,开发基于iOS系统的应用需要使用带有macOS系统的电脑,在Windows系统上是无法正常开发的,所以,首先,你需要一台Mac电脑。

这里推荐MacBookPro 16英寸 M3 Max 128G+8T深空黑版本[/滑稽]。

软件环境

软件方面,KMP要求以下几个:

开发工具 作用
Android Studio KMP 项目的主力IDE,大多数情况下我们使用它来编写我们的KMP代码。它也是Android项目的官方IDE,基于IDEA定制
Xcode 开发iOS应用程序的IDE,安装完成后接受其许可协议并打开,它会执行一些特定的任务来完成iOS开发环境的搭建,除了编写iOS平台特的代码外,大多数情况下我们不会使用Xcode
JDK 用于开发Java应用程序,包含JRE等必要的组件
Kotlin Multiplatform Mobile plugin KMM的插件,可以在Android Studio的插件市场中下载安装,具体路径为:Android Studio|Settings|Preferences|Plugins,在Marketplace中搜索并安装
Kotlin plugin 一般情况下,Kotlin插件会与Android Studio绑定。Kotlin plugin需要与Kotlin Multiplatform Mobile plugin保持兼容,具体的兼容性表参考 Kotlin Multiplatform Mobile plugin releases | Kotlin 。如果有兼容性问题需要更新插件,可在Android Studio中进行更新。

以上就是KMP所需的全部工具,建议将这些工具都安装至最新的稳定版本,以避免不必要的兼容性问题。

ps:Kotlin/Native 有时会不支持最新的Xcode,如果遇到这种问题,可以尝试安装旧版本的Xcode。Kotlin/Native 与Xcode的兼容性可以参考 compatibility guide

确认安装环境

一切准备完毕后,我们可以通过KDoctor来校验我们的环境是否有问题。与Xocde类似,KDoctor同样只能运行在MacOS系统上。

建议通过Homebrew安装KDoctor:

brew install kdoctor

你也可以选择去往 KDoctor 的 Github 主页手动下载。

安装完成后,在命令行运行以下命令校验我们的安装环境:

kdoctor

运行完成后会输出类似以下的内容:

可以看到KDoctor主要校验的就是我们上面提到几点:操作系统、Java、Android Studio以及对应的插件、Xcode以及对应的CommandLineToolscocoapods

每项检查的结果分为三种状态:

  • [✓] - Success
  • [✖] - Failure
  • [!] - Warning

如果你和我一样,之前从没有使用过Xcode,大概率会和我遇到一样的错误和警告: Current command line tools: /Library/Developer/CommandLineTools cocoapods not found,别急我们一条一条来看:

  • CommandLineTools

在 macOS 上,Command Line Tools 是一组提供在终端中使用的工具,它们对开发者来说非常有用。也是许多类型开发工作的先决条件,包括但不限于 C/C++、Python 扩展和一些 gem 包的安装。 我们按照报错的指引,前往Xcode|Settings|Locations|Locations设置一下即可。

  • cocoapods not found

CocoaPods 是一个应用于 macOS 和 iOS 应用程序开发的依赖管理工具,专门用于 Swift 和 Objective-C 编程语言的项目。它通过简化第三方库(称为 "pods")的添加和更新过程,帮助开发者管理项目依赖。

我们的第一个KMP项目并不会使用到CocoaPods,所以这个警告我们暂且忽略。

问题解决后我们再次运行kdoctor命令:

可以看到关于cocoapods仍然有警告,但已经不影响我们接下来的KMP项目了~

step 2:创建我们的第一个KMP项目

使用官方模版创建KMP项目

磨刀不误砍柴工,环境搭建完成后,我们就可以着手创建我们的第一个KMP项目了,Kotlin官方为我们提供了一套创建KMP项目的模版: KMP向导

我们只需要:

  1. 打开KMP向导 链接
  2. 选中New Projecttab,按需更改项目名称和项目id
  3. 按需选择我们需要支持的平台,此处我们选择Android和iOS
  4. 对于iOS,我们选择不共享UI,因此此处选择Do not share UI(use only SwiftUI)
  5. 点击下载按钮得到我们的第一个KMP项目工程文件

使用Android Studio打开KMP项目

将我们的「HelloKMP」项目使用Android Studio打开,左上角选择以"Project"形式查看工程目录:

工程主要包含3大模块:

  • composeApp

该文件夹包含了使用Compose Multiplatform在不同平台间共用的代码,该文件夹包含了两类子文件夹:

  1. commonMain 所有平台共享的代码
  2. androidMain or iosMainor... 平台特定代码

由于我们的项目仅支持iOS和Android两个平台,且选择了保持UI部分的平台独立性(即iOS平台使用SwiftUI构建UI),所以此处的composeApp仅针对Android平台。

  • iosApp

包含iOS应用程序,即使使用Compose Multiplatform共享UI,页需要该文件夹下的代码提供入口。iOS平台的特定代码也应存放于此。

  • shared

shared模块包含了iOS和Android的通用逻辑代码,其包含3个子文件夹:

  1. androidMain
  2. iosMain
  3. commonMain

开发时需按照代码的通用程度将代码正确存放在不同的子文件夹下。
shared文件夹下的代码会根据平台的不同生成不同的产物:在Android平台生成的就是Kotlin/JVM的代码,在iOS平台生成的就是Kotlin/Native代码。

奔跑吧,骚年

KMP项目默认包含了两个构建配置:composeAppiosApp,分别对应构建Android App和iOS App,我们分别选择两个配置,run起来看看:

ps:构建ios项目时,不要忘了启动Xcode并保持运行

step3:编写通用代码

我们来调整下代码,毕竟是我们的第一个KMP项目,我们就将当前时间展示出来以做纪念(这还不是手到擒来): 找到项目中展示文案的代码,在Greeting.kt中,我们对文案加以改造:

IDE大大的红色仿佛给了我们一个大大的逼兜:竟然找不到System类。很奇怪么?其实一点也不奇怪。

Greeting.kt位于shared|commonMain目录下,意味着此处的代码,是iOS和Android平台共用逻辑,而System是JVM特有的类,iOS平台上并不存在,所以报错也就不足为奇了。

那怎么来解决这个问题呢?这就要用到expectactual关键字了:

expect 关键字

当你在共享代码模块中需要使用某些平台特定的实现(例如,API 调用、库或者某些行为)时,你可以使用 expect 关键字来声明一个期待的声明(expected declaration)。这表明你期望每个目标平台都提供这个声明的具体实现。expect 声明不能包含实际的实现代码。

actual 关键字

对于每个平台特定模块,你需要使用 actual 关键字来提供 expect 声明的具体实现。这意味着对于共享代码中的每个 expect 声明,每个平台都必须有一个对应的 actual 实现。actual 实现包含平台特定的代码,这些代码在该平台上执行预期的功能。

例如获取系统时间戳,我们在commonMain模块下声明一个接口,然后在不同的平台上实现该接口,提供真正的、基于平台的实现方法。

kotlin 复制代码
#shared|commonMain|Time.kt
interface Time {
    val currentTime: Long
}

expect fun getTime(): Time

#shared|androidMain|Time.android.kt
class AndroidTime: Time {
    override val currentTime: Long
        get() = System.currentTimeMillis()
}

actual fun getTime(): Time = AndroidTime()


#shared|iosMain|Time.ios.kt
class iOSTime: Time {
    override val currentTime: Long
        get() = Clock.System.now().toEpochMilliseconds()
}

actual fun getTime(): Time = iOSTime()

然后就可以在Greeting.kt中获取系统的时间戳:

kotlin 复制代码
class Greeting {
    private val platform = getPlatform()
    private val time = getTime()

    fun greet(): String {
        return "Hello, ${platform.name}!${time.currentTime}"
    }
}

ps:在iOS平台获取系统时间戳时,我们使用Clock.System.now().toEpochMilliseconds()来获取。 事实上,这是Kotlin 中的一种获取当前时间戳的方式,来自 Kotlinx DateTime 库,在Android平台上也可以正常调用。上面的例子主要是为了体现expect/actual关键字的作用。

再次运行一下看看效果:

可以看到,时间戳都被正常打印出来了。

总结

通过我们的第一个KMP项目,相信你对KMP大概已经有了初步的认知。接下来,我们将继续学习KMP,打怪升级,成为一代大侠。

相关推荐
风和先行19 分钟前
adb 命令查看设备存储占用情况
android·adb
qq_3901617724 分钟前
防抖函数--应用场景及示例
前端·javascript
John.liu_Test1 小时前
js下载excel示例demo
前端·javascript·excel
AaVictory.1 小时前
Android 开发 Java中 list实现 按照时间格式 yyyy-MM-dd HH:mm 顺序
android·java·list
Yaml41 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
PleaSure乐事1 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶1 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json
getaxiosluo1 小时前
react jsx基本语法,脚手架,父子传参,refs等详解
前端·vue.js·react.js·前端框架·hook·jsx
理想不理想v1 小时前
vue种ref跟reactive的区别?
前端·javascript·vue.js·webpack·前端框架·node.js·ecmascript
知孤云出岫1 小时前
web 渗透学习指南——初学者防入狱篇
前端·网络安全·渗透·web