了解 Compose Multiplatform 已经比较久了,之前尝试过 compose-desktop 与 Android 的 jp-compose还是比较一致的。最近了解到 Compose-IOS 已经发布了 beta 版本,应该算比较稳定了,所以来尝试一下。
配置环境
开发 IOS app 必须在 MacOS 下面开发,所以此项目的前提是你必须有一台 Mac 设备。
在创建第一个 Kotlin Multiplatform 应用程序之前,您需要为 KMP 开发设置一个环境。
安装必要的工具
检查环境
要确保一切按预期工作,请安装并运行 KDoctor 工具:
- 使用 Homebrew 安装 KDoctor:
brew install kdoctor
- 安装完毕后再执行命令
kdoctor
如果环境没有问题则应该是如下信息:
❯ kdoctor
Environment diagnose (to see all details, use -v option):
[✓] Operation System
[✓] Java
[✓] Android Studio
[✓] Xcode
[✓] CocoaPods
Conclusion:
✓ Your operation system is ready for Kotlin Multiplatform Mobile Development!
如果有问题,则会在某一项上打❌,然后有相关错误信息,按照提示操作就行。
使用向导创建项目
- 打开 [Kotlin Multiplatform](Kotlin Multiplatform Wizard | JetBrains) 向导 。
- 在 New project 选项卡上,将项目名称更改为 “FirstKMP”,将项目 ID 更改为 “com.example.kmp”。
- 确保已选择 Android 和 iOS 选项。
- 单击 Download 按钮并解压缩生成的存档。
导入工程
同步结束后我们来看下工程结构:
-
/composeApp是用于在 Compose Multiplatform 应用程序中共享代码的目录。 它包含几个子文件夹:commonMain是用于所有目标通用的代码。- 其他文件夹是用于仅在文件夹名称中指示的平台上编译的 Kotlin 代码。
例如,上图的
androidMain和iosMain分别用来处理自己平台的独有业务逻辑。另外还可以创建其他平台,如:webMain、desktopMain 等。
-
/iosApp包含 iOS 应用程序。即使你在使用 Compose Multiplatform 共享 UI, 你仍然需要这个 iOS 应用程序的入口点。这也是你应该为项目添加 SwiftUI 代码的地方。
commonMain 源集使用通用的 Kotlin 代码,平台源集使用特定于每个目标的 Kotlin 代码。Kotlin/JVM用于 androidMain 和 desktopMain。Kotlin/Native 用于 iosMain。
commonMain 源代码在构建为 Android library 时被视为 Kotlin/JVM。在构建为 iOS framwork 时被视为 Kotlin/Native。
运行应用
可以在 Android、iOS虚拟机或真机上运行该应用程序。不需要按任何特定顺序运行应用程序,从您最熟悉的平台开始。
运行 Android app
对于 Android 开发人员应该是无比熟悉,不需要你做任何事,直接选择需要运行的目标设备,然后点击“运行”按钮就行
运行 IOS app
有时候可能因为Xcode环境问题,这里的iosApp 会标记着一个红色的x号,提示找不到设别,或者其他关于Xcode的问题,此时可以直接点击iosApp module 下的 iosApp.xcodeproj ,可以直接用Xcode 来打开编译。
| |
|
然后点击菜单Edit Configrations... 指定一个 Execution target,如:iOS 15,然后就可以点击“运行”按钮运行了。
这样我们的第一个 demo app 就成功运行了,对比下 ios 与 Android 的差异就是屏幕显示的系统版本分别是 iOS 18.0 和 Android 34,我们来看看这部分的差异如何实现的。
iOS 与 Andriod 的差异实现
interface Platform {
val name: String
}
expect fun getPlatform(): Platform
这是在 commonMain 的一个文件,它定义了一个接口和一个 top level 函数,这跟我们之前接触的 kotlin 一样。不同的是 getPlaform 方法前有一个关键字 expect,这个关键字在 KMP 中很重要,它的声明表示公共代码预期每个平台的不同实际actual实现。在此处其作用于函数。但是,它也可以应用于类、对象、注释等。(有关更多信息,请参阅此处)
class Greeting {
private val platform = getPlatform()
fun greet(): String {
return "Hello, ${platform.name}!"
}
}
我们来看看调用部分的代码,这几行代码很简单,相信大家都看得懂。调用getPlatform()是希望得到一个Platform对象实例,而因为getPlatform()前面有 expect 关键字,所以它在不同的平台上有不同的代码实现,我们继续看。
// Platform.android.kt
class AndroidPlatform : Platform {
override val name: String = "Android ${Build.VERSION.SDK_INT}"
}
actual fun getPlatform(): Platform = AndroidPlatform()
// Platform.ios.kt
class IOSPlatform: Platform {
override val name: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion
}
actual fun getPlatform(): Platform = IOSPlatform()
Platform.android.kt 文件在 androidMain 模块, Platform.ios.kt 在 iosMain模块。可以看到它们分别有不同的 actual 函数,然后当然也有着不同的实现,在此处就是分别获取了不同平台的版本号。这样便轻松的实现了各自独占逻辑,还是比较容易理解的吧。
Demo 展示
最近玩羽毛球比较多,大家希望组织一些小对抗,增加运动的趣味性。所以就有了羽毛球选手随机抽签、分组对抗的需求,需求比较简单于是就手撸了一个。
这里只展示了 iOS 的效果,实际 Android 与 iOS 是一模一样的,就不展示了。
源码在这,有需要的可以自取。
最后,希望此篇文章对帮助大家入门 Compose for iOS 有帮助。