谷歌社区说|聊聊Compose跨平台与KMM

发布时间:2023年12月27日

大家好我是黄林晴,也是图书《Android Jetpack开发:原理解析与应用实战》的作者。上一次在社区分享还是在三年前的Android 11见面会上,本次为大家分享的主题是Compose Multiplatform和KMM。这里是本次分享的文字版。

前言

上个月JetBrains 发布了 Compose Multiplatform for iOS Alpha 版本,这让许多热爱跨平台的开发者喜出望外。但是也有许多开发者可能还没有了解过Compose Multiplatform和KMM,那么本次分享将通过以下几点来介绍Compose Multiplatform 与KMM,让我们一起体验Kotlin跨平台的魅力。

  • Compose Multiplatform 与 KMM的关系
  • Compose Multiplatform 与 KMM的实践
  • 开发者该如何选择

这里需要先说明的是,本次分享我们只会从使用的角度去分享,作为一次跨平台技术的普及,不会涉及跨平台的底层原理,比如为什么可以跨平台这些深奥的道理。为什么不讲这些呢?原因很复杂,简单的说就是我不会。

Compose Multiplatform 与 KMM的关系

要Compose Multiplatform 与 KMM的关系,我们只要来分别了解Compose Multiplatform 与 KMM分别是什么就行了。

KMM是什么

KMM的全称是Kotlin Multiplatform Mobile,与之对应的是KMP—Kotlin Multiplatform Project,其实就是一个是Kotlin移动端跨平台,一个是Kotlin跨平台项目的集合。KMM更像是营销术语,我们不用纠结Mobile这个词,你要知道的是,下文我们所说的KMM就是指的Kotlin跨平台不仅限于移动端就行了。

KMM可以简化多平台应用程序的开发。通过KMM,开发者可以在 iOS 、 Android、Desktop与Web 应用程序之间共享业务逻辑的通用代码,在必要时也可以编写特定于平台的代码。所以,KMM只负责跨平台下的业务逻辑部分。

比如这张图中的数据层、网域层等都可以使用KMM来完成公共的业务逻辑。

在KMM早期推出来的时候,那个时候Compose Multiplatform还没有发布,所以大家都觉KMM很鸡肋,因为90%的开发者认为移动端的主要工作都在编写UI上,跨平台不能跨UI叫做哪门子的跨平台?

但是,其实这种观点是不正确的,很多业务逻辑比如日志系统、埋点等业务使用KMM还是非常有利的。

后来Compose Multiplatform的出现弥足了KMM的短板。那么Compose Multiplatform又是什么呢?

Compose Multiplatform是什么

Jetpack Compose是Android官方推出的声明式UI框架,Compose Multiplatform是由JetBrains维护的Compose跨平台框架,专注于UI跨平台,同样支持iOS、Android、Web、Desktop等。

有了Compose跨平台,便弥补了KMM的缺陷。

我始终觉得有一个尴尬的问题就是,要说Compose Multiplatform与KMM不是一个东西吧,他们确实不是一个东西,毕竟版本的更新、维护者都不同。但是毕竟Kotlin底层对Native、JS的支持都是Compose Multiplatform的基础。所以我更希望有一天他们可以合并,不管是版本的更新还是插件的支持都可以统一。所以我更喜欢直接称他们为Kotlin全平台。

那么其实,你现在也已经知道了KMM与Compose Multiplatform的关系。接下来我们来看Compose Multiplatform 与 KMM是如何实践的。

Compose Multiplatform 与 KMM的实践

由于Compose Multiplatform 与 KMM一个复用UI一个复用业务逻辑,所以我们分别来看是如何实践的。

实践KMM

KMM用于实现业务逻辑部分,这里我们只以Android和iOS两端为例。这里还是要再次重申一下,Compose Multiplatform 与 KMM是可以独立使用的,也就是说在使用KMM的时候可以分别写Android、iOS的原生UI,在使用 Compose Multiplatform跨平台的时候也可以分别实现其他端的业务逻辑。

创建项目

在Android Studio中我们可以借助Kotlin Multiplatform Mobile plugin插件来快速的创建支持KMM的项目。

安装好插件后,打开Android Studio我们可以直接创建支持KMM的项目。

创建的时候会让我们填写模块的信息

创建好项目后,生成的项目目录结构是这个样子的。

androidApp、iOSApp就是对应的Android、iOS各自的代码库,shared模块,即存放Android、iOS公共业务逻辑的部分。

KMM插件只为我们创建了Android和iOS的源集,如果想创建其他平台的可以自己创建文件夹然后指定目标平台。

创建好项目之后我们来看如何处理公共的业务逻辑。

公共业务逻辑

双端完全可以共用的逻辑我们直接放在commonMain文件夹下即可。开源库的依赖我们写在commonMain目录下。

这里添加网络请求库Ktor和序列化的依赖,因为是Kotlin跨平台嘛,Ktor是Kotlin推出的网络请求库,所以肯定使用Ktor是最佳选择。

这段代码呢,就是Ktor这个网络请求框架的基本用法,我们不做过多解释,在这里我们定义了一个getData方法,用于获取「鸿洋」大佬「wandroid」中的「每日一问数据」。

然后我们各自在编写Android或者iOS的UI代码接收数据即可。我们这里直接将返回展示展示在文本中,最终实现的程序是这个样子的。

这个UI我们将在后面的Compose Multiplatform 中实现。这样我们就实现了双平台一个简单的数据请求的例子。

社区对KMM的支持

目前官方许多库都已经支持了跨平台,比如我们刚刚使用的网络请求框架Ktor、依赖注入Koin还有序列化组件等。

除此之外,对Android开发开发来说,最友好的消息是从去年10月份开始Jetpack也开始支持跨平台了,不过当前Jetpack支持的跨平台组件只有三个:Annotations、Collections、DataStore。

当然还有一些比较有名的App也开源了一些组件比如Cash App开源了Paging分页库。

与AndroidX下的Paging设计一样,paging-common模块提供存储层、视图模型层;paging-runtim模块提供UI层。

最主要的是,paging-common中的API与AndroidX 下的API完全相同,仅仅是将包从androidx.paging迁移到了app.cash.paging中,所以这部分的使用我们直接按照AndroidX中的Paging使用即可。

但是在实际项目中,仅依靠社区的支持可能没办法满足所有业务。当然也有一些开源贡献者开源了一些组件,但是为了确保稳定性,我们一般需要自己去单独实现各自的业务逻辑,那么我们如何确保使用同一套API呢?

expect与actual

我们要依赖Kotlin中的expect与actual关键字。expect是我们期望实现的方式,actual是实现方式,有点类似接口与实现类。比如我们现在要实现业务逻辑:打开系统蓝牙。

首先我们要在commonMain中使用expect定义这个接口

然后我们在shares模块下的androidMain、iOSMain目录下各自实现打开蓝牙的方法。

这样我们就确保多平台下使用同一API来调用,调用方不需要关注具体的实现。那么到这里呢,KMM我们就了解的差不多了,从上面的了解可以看出 其实KMM当前是可以使用在实际项目中的,不过我们可以再等等,Kotlin的RoadMap中说今年会发布正式版本,我们可以一起期待一下。接下来我们再来一起实践Compose Multiplatform。

实践Compose Multiplatform

Compose Multiplatform 专注于UI复用,我们前面提到过,有个尴尬的问题就是KMM与Compose Multiplatform 的版本和插件是不统一的。我们可以借助KMM插件在Android Studio中快速的创建KMM项目,但是当前如果我们想快速创建Compose Multiplatform 项目只能借助新版的IDEA。

创建项目

下载最新版本的IDEA,创建Compose Multiplatform项目,但是更尴尬的是,由于当前iOS还在alpha阶段,所以IDEA并不能创建iOS平台的项目。

所以我们我们现在如果想使用Kotlin全平台有两种方式:

  • 使用IDEA创建项目,添加KMM依赖配置
  • 使用Andrioid Studio创建项目,添加Compose Multiplatform的配置
  • 使用官方提供的模板项目

这里我基于刚刚创建的KMM项目,在KMM的基础上添加Compose Multiplatform的配置。

项目配置好之后,我们接着刚刚查询每日一问的功能来实现,当然在配置的时候肯定踩了很多坑,这些我都记录在我的博客中了。

实现双端的网络数据显示

iOSApp.swift中的代码是这个样子的。

Main_iosKt.MainViewController是通过新建在shared模块iOSMain目录下的main.ios.kt文件获取的,代码如下所示:

所以,我们可以在shared模块中的commain目录下编写解析网络数据并现实的Compose方法,然后在Application下调用就行了。

这个代码大家肯定都能看懂,和Jetpack Compose是完全一致的。通过Message方法将数据展示出来,这里只将作者与标题内容显示出来,代码如下所示:

然后这样我们就可以运行Android和iOS程序了,这里要注意的是借助KMM插件我们可以直接运行iOS程序,但是有个前提就是仍然要安装Xcode,Android和iOS效果如下图所示。

我们可以看到页面效果是完全一致的,并且就页面中这个功能来说,达到了业务逻辑和UI的百分之百复用。怎么样是不是泰酷辣!

Desktop与Web

我们上面都是以Android和iOS为例,其实Desktop与Web端也是一样的,相对比来说我觉得Desktop已经比较成熟了,UI也是可以完全复用Jetpack Compose。我又分别实现了Desktop与Web在此示例上的效果。

这里对Web要多说一点,在早期的时候Compose for Web是使用Compose HTML来实现的,Compose HTML 是一个面向 Kotlin/JS 的库,它提供了用 HTML 和 CSS 创建 web 用户界面的 Composable 组件,所以割裂问题非常严重,不能说不能与Jetpack Compose复用,只能说和他毫无关系。

比如我们实现图中的数据显示Compose HTML写法是这样的,当时看到这个是比较崩溃的。好在Kotlin在1.8.20版本中推出了Kotlin/Wasm,最新的Compose for Web 是基于Kotlin/Wasm的,当前处于试验阶段。页面可以完全与Jetpack Compose复用,所以大家注意一下Compose HTML的写法就不要再学习了。

官方给出了一些Compose Multiplatform的模版,也有Kotlin/Wasm的模板,但是唯独没有Compose Wasm for Web的模板,所以,我自己在github上开源了一个模板,感兴趣的大家可以去使用。

和刚刚提到的组件问题一样,随着Compose Multiplatform技术的成熟,早晚官方会推出一个新的插件来同时支持KMM和Compose Multiplatform。

与原生UI的互操作性

在使用Jetpack Compose开发Android的时候,有些场景下我们可能需要让Jetpack Compose与XML 嵌套使用,那么在跨平台中肯定也会存在这种场景,在iOS中可以通过使用 UIKitView,在共享用户界面中嵌入复杂的特定于平台的小部件,如地图、 Web 视图、媒体播放器和照相机等。

总之,这些肯定都不会是阻碍Compose Multiplatform跨平台发展的因素。

开发者该如何选择

当前与Compose跨平台竞争的主要主力应该是Flutter,很多人总喜欢将他们进行比较,现在比较肯定是Compose Multiplatform肯定不如Flutter的,但这样比较也有点欺负Compose Multiplatform。毕竟Compose Multiplatform还很年轻。

当然这是一个非常开放的话题,我只表明个人观点。Flutter永远都会存在语言壁垒的问题,但是KMM和Compose Multiplatform对Android开发者来说几乎是赠送的。当然了现在存在两拨人可能阻碍他们使用KMM和Compose Multiplatform。

  • 没有使用过Jetpack Compose

对于没有使用过Jetpack Compose的这部分人来说,其实我是可以完全理解的,一些组件的支持,比如地图、WebView等可能还需要一定的时间,毕竟现在使用XML是完全没有问题的。还有一部分人呢是没有过Kotlin。

  • 没有使用过Kotlin

排除从事Farmework或偏低层的这部分人,其实我是完全没有办法理解甚至是有些无语的。很多人告诉我的理由都是Java也能用啊、老板不让用啊、公司项目陈旧啊,其实这些放到现在都是借口了。

已经在使用Kotlin的,我建议可以学习下Jetpack Compose,一来这是一个趋势,二来它会扩展你的跨平台技能。如果你想在未来几年内仍然从事Android开发,我觉得是没有理由拒绝的。

最后

最后,不破不立,这句话与大家共勉。

好了。本次的分享到这里就结束了,大家可以关注我的公众号《Android 技术圈》,我将持续分享跨平台等Android领域的技术~,期待我们下次再见!

文章来源:https://blog.csdn.net/huangliniqng/article/details/135238509
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。