在前面的文章中,我们一再强调Jetpack Compose是一个声明式的UI框架,尽管我们都是基于Android开发来实战的,但Compose并不局限于Android开发,它其实与特定的开发平台没有关系,是可以做到跨平台开发的。事实上JetBrains早就已经准备好了一套工具,以让Compose跨平台,开发多端应用,跻身于大前端的一员。今天就来学习一下如何使用Compose进行大前端开发。
缘起
时光荏苒,白云苍狗,自乔帮主发布iPhone开启移动互网联至今已有十余载。对于互联网应用来说,早已从最初的Android加iOS两端并行,发展到现在的大前端时代。时至今日,不论大厂小厂,多端拉齐(Web,Android, iOS, Desktop,鸿蒙)已经是一个标配和强需求。那么如何减少多端的重复开发,如何跨多端开发就成了一个永不过时的研究方向。从最初的Mobile H5,到Hybrid App,再到React Native,再到后来的Flutter,大前端已经得到了长足的发展。得益于Kotlin Multiplatform(KMP),Compose也有了跨端的能力,跻身于大前端工具之列。
在深入主题学习之前,我们先来理解一下重要的概念。
概念理解
为了避免混淆和加强理解,需要对一些概念进行澄清。
概念 | 缩写 | 说明 | 开发者 |
---|---|---|---|
Jetpack Compose | Compose | 基于Kotlin语言的声明式UI开发框架,与平台无关,源于以及主要用于Android开发 | |
Compose Multiplatform | CMP | 用于把Compose转化为多端的一个框架 | JetBrains |
Kotlin Multiplatform | KMP | 把Kotlin编译为多端的框架,这是Compose能跨平台的根基 | JetBrains |
为了简便,在后文以及以后的文章中将使用缩写。虽然严格来说CMP专指把Compose转化为多端的UI框架,但大部分场合也用它来代指Compose跨端开发,后面也会这样用。
注意: 在早些时候,也就是在JetBrains刚推出KMP的时候,仅针对和支持Android和iOS两个平台,所以当时就叫做Kotlin Multiplatform Mobile,缩写为KMM,后来也能编译出桌面(Desktop)和Web端了,就把Mobile去掉了,就是现在的KMP,代表Kotlin Multiplatform。所以,如果 在其他地方看到了KMM,把它当成KMP就可以了。
Compose大前端技术栈
在继续深入之前,捋捋技术栈,从大的角度来了解一下用到的技术工具的关系是很有必要的。
仍是用Jetpack Compose来写UI,用Kotlin来写业务逻辑,这是个是没有变的。而Compose Multiplatform(CMP)相当于是一个转换工具,能把Compose写的UI转变成为不同平台的UI实现。编程语言用的是都是Kotlin,最终要依赖KMM编译出具体平台的目标文件(Target)。所以,它们三个是依赖关系Compose依赖CMP,它们又都依赖KMM。
最先出现的当然是编程语言Kotlin,之后Google推出了声明式UI框架Jetpack Compose,采用了Kotlin语言。随着Kotlin的发展,JetBrains推出了KMP,让Kotlin实现跨多端,在这之后又基于Compose,推出了CMP,因为都是Kotlin语言,与KMP一起凑成了Compose/Kotlin的跨端。现在谷歌也与JetBrains紧密的合作,一起努力把Compose往前推进,去挑战React Native和Flutter。
学习成本并不高,因为对于开发者来说仍旧是Compose和Kotlin,CMP和KMP是透明的,它们以插件和依赖库的形式存在,没有额外的学习成本。当然,这对Android开发同学来说更为友好一些,因为大部分Android开发同学早已掌握了Compose和Kotlin。
开发环境搭建
CMP的技术栈并不复杂,如果已具备Android开发环境,那基本上就齐活儿了,这再次说明CMP对Android开发同学是相当友好的。开发用的IDE就是Android Studio,编译工具用的是Gradle,这对Android同学来说已经是标配了,不熟悉的同学可自行Google。
唯一需要安装的就是KMP的插件(plugin),也即Android Studio中,到插件市场搜索Kotlin Multiplatform,这是JetBrains官方提供的插件,找到后可放心安装,之后重启AS即可。
以上是通用开发配置,但如果目标平台是iOS就略麻烦一些。此小节后面的内容,仅当目标平台包含iOS时需要,否则可以跳过。
注意: Mac虽然也是水果系统,但Mac属于桌面端(Desktop),如果为Mac构建应用要选择Desktop为目标平台。
因为水果的生态是封闭的,要想构建iOS就必须要用Xcode,而Xcode只在Mac上面才能用,所以要想构建iOS端应用,必须要用Mac来开发,而且要是新一点的Mac(三年以内)。然后安装最新的Xcode就差不多了,官方提供了一个Mac上为iOS环境的检查工具kdoctor(用brew install kdoctor来安装),但其实如果配置了Android开发环境后,再装上Xcode就够了。
注意: 如果是比较旧的Mac,Big Sur以前的,就不用再折腾了,无法构建iOS,因为构建iOS需要Xcode 12.5,而Xcode 12.5又至少需要macOS 11.7(即Big Sur)。环境检查工具kdoctor本身也是要求Xcode 12.5以上,建议在安装之前可以先用brew info kdoctor来检查一下。水果就这点不好,硬件和软件更新都特别快,向后兼容又不友好,最多支持三个版本(时间跨度在3年左右)。
创建一个多端应用
环境配置好后,就可以开始创建CMP了,官方提供了一个KMP项目创建向导可以方便的生成一个项目模板。需要注意的是就是,如果要构建iOS,一定要勾选『Share UI』。
注意: 要想构建iOS目标需要较新的Mac才可以,如果开发环境不是Mac,或者Mac较旧,就不用钩选iOS了,因为选了也无法构建出来和运行目标产物。
在创建向导中配置好后,点击下载就可以了。解压之后,用Android Studio打开(File | Open)项目文件,就可以开始CMP的开发了。注意,要直接打开解压出来的根目录,而不是里面的某个子目录。因为AS打开的项目默认使用专为Android开发优化后的视图结构「Android」,为了更方便需要切换为「Project」。
可以看一眼项目结构,与常规的Android项目相比差不多,包含了两个模块(module):
- composeApp 这是最主要的模块,可以说东西都在这里面。它是一个Kotlin模块(Kotlin module),包含了多端共用代码,以及不同平台的定制代码。使用Gradle来构建,用Gradle的脚本来描述构建方式。
- iosApp 这是一个完整的Xcode项目,主要用于构建iOS目标,它会依赖于composeApp。
注意: 如果在项目创建向导中没有钩选iOS,将不会有模块iosApp,以及composeApp中的iosMain。
重点需要关注composeApp,它包含了几个源码集合(source sets):
- commonMain 这是最主要的集合,包含共享代码,由一个composable函数作为入口开始(如App())开始。这里应该是项目的主要代码集合。
- androidMain 包含与Android平台相关的代码,包括入口(如Android manifest和Activity),入口会调用commonMain中的入口composable。以及提供平台特定的定制化实现。
- desktopMain 桌面端的入口,以及定制化实现。
- iosMain 水果移动端的入口,以及定制化实现。
- wasmJsMain Web端的入口,以及定制化实现。
注意: 源码集的具体数量取决于创建项目时钩选的目标平台。
源码集合(source set)构建工具Gradle的一个概念,它包含逻辑上相关的一坨源码文件,资源文件,以及其依赖,对于Android开发同学来说这个概念并不陌生。
这种项目源码集合关系是由KMP定义的,编译构建的时候common部分会编译成为一个依赖组件,平台部分把common当成一个依赖使用,然后最终构建出目标产物,详细的过程可以看KMP的文档。
这个模板有默认的页面,可以看一下,打开文件commonMain中的App.kt,它包含一个composable函数App(),这就是CMP的入口,可以从这里开始用Compose写应用了。
构建与运行
项目创建向导创建出来的模板项目,包含了基本的页面,可以直接构建和运行。
注意: 首次打开项目会比较慢,这是因为要下载Gradle工具链以及项目的依赖,视网络情况,可能需要几分钟到十几分钟不等,之后就能秒开。
注意: 创建出来的项目依赖用的都比较新,比如像Android开发插件AGP可能会用8.5.2,但AGP的版本受制于Android Studio,AGP与AS的兼容对应关系可以看这里。如果使用的AS版本较旧,需要调整AGP的版本。
待Gradle sync完成之后,就可以运行了。
运行Android app
对于Android app来说可以直接运行,在运行配置那里选择「composeApp」,连上手机(或者模拟器),运行就可以了。
运行桌面端(Desktop)App
桌面端没有默认运行配置,需要创建一个。在菜单中编辑运行配置(Run | Edit Configurations),点左上的加号,选择「Gradle」,输入个名字如「desktopRun」,然后在配置那一侧中的「Tasks and arguments」输入:
1
|
|
之后,选择「desktopRun」运行即可。
运行iOS app
如果选择了iOS的话,也有默认运行配置,可直接运行。但水果的东西必须依赖于水果的工具,所以要先打开Xcode,打开就行,放在一边不用做啥。然后回到AS,选择「iosApp」,运行,如果顺利,在Xcode那头就会启动iOS的模拟器,并运行App了。
注意: 要想运行iOS,Xcode版本必须要在12.5以上,因为iOS构建方式是基于Xcode 12.5的。
运行Web app
Web端也没有默认配置,需要像桌面端那样创建一个,同样是Gradle,区别在于命令不一样:
1
|
|
然后,运行,这会开启一个本地server,如果浏览器没有自动打开的话,就手动打开浏览器,并输入「localhost:8080」,就能看到。
注意: 如果开发平台是Mac,运行Web app时会有编译错误:
1
|
|
可以通过修改构建指令参数,添加--watch-fs来解决:
1
|
|
或者添加Gradle选项,以对所有的构建配置命令都生效:
1
|
|
但是,无论是--watch-fs,还是Gradle选项,对于macOS 12(Monterey)以后才生效,详见Gradle文档。
到此,应该说CMP的开发已经完全就位了。
总结
CMP配置简单,上手较快,前景光明,相信通过本文的学习可以了解并完全上车CMP开发了,还等啥呢赶紧上手撸一撸吧!