美文网首页
跨平台还能怎么玩?试试 Kotlin Multiplatform

跨平台还能怎么玩?试试 Kotlin Multiplatform

作者: 王晨彦 | 来源:发表于2023-05-25 11:17 被阅读0次

    前言

    说到跨平台,我们很容易联想到 ReactNativeFlutter 等业内比较有名的框架,通过在不同平台复用一套代码,从而提高生产力,同时保证各端逻辑的一致性,他们确实做到了。但是,目前的跨平台框架都无法做到完美复用,比如双端 UI 上的差异,导致还需要写很多适配代码,还有一个比较核心的问题,无法媲美原生性能。

    简介

    那 Kotlin Multiplatform Mobile(以下简称 KMM)又是什么呢,先看下官方的介绍

    Kotlin Multiplatform Mobile 是一个用于 iOS 和 Android 应用开发的 SDK,允许您为网络、数据存储和分析以及 Android 和 iOS 应用的其他逻辑维护一个共享代码库。
    

    不同于 Flutter 这样的完整跨平台框架,KMM 不包含渲染引擎,不支持 UI 层的代码共享,而像网络请求、数据解析和存储,以及一些 UI 无关的业务逻辑,都可以使用 KMM 共享代码。

    有些同学可能也听说过 KMP、KN等,它们和 KMM 又是什么关系?

    简单来说:

    - KMP 一般指的就是 `Kotlin Mutiplatform`,可以认为是 Kotlin 跨平台的全集,包括 KMM 移动端跨平台和 `Kotlin JS` Web 跨平台
    - KN 一般指的是 `Kotlin Native`,KN 是将 Kotlin 编译为 Native 二进制文件的技术,甚至可以在没有虚拟机的情况下运行,例如 KMM 上的 iOS 就是使用了 KN 的能力
    - KMM 是利用了 JVM 和 KN 能力实现的针对 Android 和 iOS 平台的 Kotlin 框架:Android(`Kotlin/JVM`)和 iOS(`Kotlin/Naitve`)
    

    熟悉 Android 开发的同学应该有所了解,KMM 并不是什么新鲜玩意,它在2020年就发布了第一个版本,基于 Kotlin 1.4 版本,不过由于一直处于实验阶段,因此使用和了解的人比较少。

    那么为什么今天又提起它了,原因是它在2022年10月发布了 Beta 版本,同时 Android 官方宣布 Jetpack 开始要支持 KMM 了,目前 CollectionsDataStore 已经可以通过依赖 -dev01 版本在多平台上使用,也就意味着 KMM 的社区支持有了官方保证,另外根据 JetBrains 的官方信息,如无意外,KMM 的稳定版会在 2023 年发布,因此距离 KMM 可以投入生产已经很接近了!

    结构

    在开始之前,我们先来了解一下 KMM 的开发模式。

    每个 KMM 项目都包含三个模块:

    • Shared 是一个 Kotlin 模块,其中包含 Android 和 iOS 应用程序通用的逻辑,是在平台之间共享的代码。它使用 Gradle 作为构建系统,帮助您自动执行构建过程。共享模块内置到 Android 库和 iOS 框架中。
    • AndroidApp 是一个内置到 Android 应用程序中的 Kotlin 模块。它使用 Gradle 作为构建系统,AndroidApp 模块依赖于共享模块,并将共享模块用作常规的 Android 库。
    • iOSApp 是一个内置到 iOS 应用程序中的 Xcode 项目。它依赖于并使用共享模块作为 iOS 框架。共享模块可以用作常规框架或 CocoaPods 依赖项。
    image.png
    image.png

    Shared 模块由三个 SourceSet(源集) 组成:androidMainiosMaincommonMain。源集是一个 Gradle 概念,用于逻辑上组合在一起的许多文件,其中每个组都有自己的依赖项。在 KMM 中,共享模块中的不同源集可以针对不同的平台。

    尝试

    作为逻辑层跨平台,我们主要关心网络请求、数据解析、数据缓存、多线程等问题。

    这里用一个简单的 demo 来尝试一下 KMM,功能是展示天气信息,支持从网络和数据库缓存获取数据,网络获取成功后对数据进行缓存,然后即可展示缓存数据。这里除了UI之外,全部用 KMM 实现。

    数据定义

    KMM 支持使用 kotlinx.serialization 插件对数据进行序列化和反序列化。

    image.png

    用过 Gson 的同学应该很熟悉,和 Gson 的使用方式几乎完全一样,除了导入的包名不同。

    网络请求

    在 KMM 中,我们使用 Ktor 来进行网络请求。

    Ktor 是一个轻松构建联网应用(web 应用、 HTTP 服务、 移动应用以及浏览器应用)的框架。 现代的联网应用需要异步化来提供最佳的用户体验,而 Kotlin 协程为此提供了极其简便的方式。
    Ktor 的目标是为联网应用提供端到端的多平台应用框架,虽然还没有完全实现。目前支持 JVM 客户端与服务器场景,以及 JavaScript、iOS 与 Android 客户端,而我们(官方)正努力将服务端支持引入到原生(native) 环境,并将客户端支持引入到其他原生平台。
    

    可以看出,Ktor 就是为了跨平台而生的。

    使用非常简单

    image.png

    通过泛型直接反序列化为实体,非常方便。

    有些同学可能要问了,JSON 序列化效率太低了,能不能用 ProtoBuf

    当然可以,Ktor 目前已经支持 JSONXMLCBORProtoBuf 序列化格式,只需替换依赖即可,由于 demo 使用的 API 接口使用的是 JSON 格式,因此不再演示 Protobuf 格式的解析方式。

    数据缓存

    前面提到,Jetpack 的 DataStore 组件已经支持 KMM,今天我们来看一下,在 KMM 中如何通过 DB 缓存数据。

    这里我们要借助 SQLDelight 这个开源框架,它出自 Square,与 OkHttp 同源。

    SQLDelight 从您的 SQL 语句生成类型安全的 Kotlin API。它在编译时验证您的 Schema、Statements 和 Migrations,并提供如 Autocomplete 和 Refactoring 等 IDE 功能,使编写和维护 SQL 变得简单。
    

    首先,我们要定义 SQL 文件,用于声明表结构和 CRUD 语句,然后 SQLDelight 插件会帮我们自动生成代码。

    image.png

    为了方便,我们的数据库中仅定义一个 json 列,不再定义每个属性,数据库存储前先通过 JSON 序列化。这里仅用于演示 SQLDelight 的使用,请大家不要效仿🐶。

    Sync 一下,即可在 build 目录中看到生成的文件,这里不再一一展示。

    image.png

    值得一提的是,由于在不同平台上 SQL 的实现也不一样,因此需要在 androidMainiosMain 源集中分别创建数据库驱动的实现,不过这些 SQLDelight 已经封装好了,我们只需要导入即可。

    这里需要用到 KMM 中的一个常用关键字 expect,声明了 expect 的类,即表示需要在各个平台上分别实现,详见 Connect to platform-specific APIs | Kotlin

    commonMain 中声明 DatabaseDriverFactory

    image.png

    androidMainiosMain 分别实现,并添加 actual 关键字

    image.png

    最后,创建 Database 类来封装对数据库的操作

    image.png

    至此,我们已经可以使用 KMM 完成天气数据的网络获取和数据库缓存。

    image.png

    UI 的代码这里不再展示,我们来看一下最终效果

    image.gif

    小结

    从可用性方面来说,在 KMM 上可以使用开源框架进行网络请求、数据缓存等,常见的数据格式都已经支持,并且这些开源库都已经提供稳定版本;从易用性方面来说,作为 Androider,几乎是0成本上手,且开源框架的使用都非常简单,甚至比 Android 原生的开源框架(OkHttpRoom 等)使用更简单,iOSer 可能需要一定的学习成本。综上,我认为 KMM 在功能上已经可以满足基础的逻辑层跨平台诉求,在使用上也非常简单。

    最后附上 demo 源码

    Features

    易上手

    由于使用 Kotlin 语言,因此 Android 同学不需要学习成本,iOS 同学需要了解 Kotlin 的语法,即便如此,作为一门现代语言,Kotlin 还是非常容易上手的!

    性能

    作为跨平台框架,性能是一个关键指标。

    在 Android 上,Kotlin 代码会被编译成 JVM 字节码,即 class 文件,最终打包到 dex 中,因此可以认为和原生性能一致。

    image.png

    在 iOS 上,Kotlin/Native 编译器会将 Kotlin 代码转换为所谓的 LLVM IR,这与 Swift 编译器的形式相同,最终,会使用和 Swift 相同的工具链,将这个 LLVM IR 会被转换为原生可执行的二进制文件。

    image.png

    官方的流程图

    image.png

    由于使用原生同样的编译形式,KMM 相比其他跨平台框架,在性能上更有优势。使用根据 JetBrains 官方的描述,KMM 目前已经非常接近原生应用的性能,甚至已经可以和原生持平,而且,他们还没有使用所有的优化手段,未来, KMM 的性能将有进一步提升。

    可能有些同学会问,KMM 与 Rust 性能对比如何?
    

    原生互操作

    不论是在 React Native 还是 Flutter 上,JavaScript/Dart 与原生代码相互操作都是非常麻烦的,需要通过“桥接通讯”来实现。

    由于 KMM 可以编译为和原生库一样的形式,因此,可以和原生开发语言直接相互调用
    同时,KMM 代码也可以很容易的打包为 Library,提供给其他 APP 使用。

    image.png

    轻量

    由于 KMM 最终的编译产物是基于双端标准组件输出,因此无需内置多套引擎 (runtime),包体积增量更少,同时 iOS 端审核被拒风险也比较小。

    UI 跨平台*

    你以为 KMM 会止步于逻辑层跨平台吗?

    NO,根据官方规划,KMM 的 UI 跨平台功能已经在 KMM 的计划之中,并附带了一张效果图

    image.png

    关注 Compose 的同学应该知道,Compose Multiplatform UI 跨平台框架在 2021 年底就已经发布了稳定版,支持 Android、Web 和桌面的 UI 跨平台,只是迟迟没有支持 iOS,现在只需要解决在 iOS 上的复用,虽然目前还没有任何阶段性成果,但是也值得期待!

    有些同学可能对 Jetpack ComposeCompose Multiplatform 还不太了解,这里简单介绍下

    `Jetpack Compose` 是 Google 针对 Android 推出的新一代声明式 UI 工具包,完全基于 Kotlin 打造,天然具备了跨平台的使用基础。
    JetBrains 以 `Jetpack Compose`(后文简称 `compose-android`)为基础,相继发布了 `compose-desktop` 和 `compose-web` ,使 Compose 可以运行在更多不同平台。
    

    小结

    KMM 使用 Kotlin 语言,对 Android 开发者十分友好。

    在性能方面,由于目前使用 KMM 的产品比较少,因此没有找到真实可信的测试数据,我们姑且相信官方介绍😂。

    根据官方的描述,KMM 在 iOS 和 Android 上分别都会转为和原生一致的中间产物,因此接近原生性能,而且 KMM 团队后续还会着重优化 KMM 的性能,未来可期!

    另外,可以和原生语言直接相互调用也是一大优势,同时基于 Kotlin 到原生的转换能力,KMM UI 跨平台能力同样值得期待!

    不足

    并发

    在 Android 上,我们可以很方便的使用基于 JVM 线程池的 Kotlin Coroutines 来进行并发操作,但由于 Kotlin/Native 和 JVM 的内存模型差异,导致 iOS 上的协程只能使用单一后台线程,官方有一篇博客专门对 Kotlin/Native 的内存管理做了介绍 。

    对此,Kotlin 团队重新设计了 Kotlin/Native 上的内存管理器,并在 Kotlin 1.7.20 版本默认启用

    新的 Kotlin/Native 自动内存管理器解除了线程之间对象共享的现有限制,并提供完全无泄漏的并发编程原语,这些原语是安全的,不需要开发人员的任何特殊管理或注释。
    

    看起来 Kotlin/Native 已经解决了并发的问题,不过是否彻底解决还需要线上产品来验证。

    总结

    本文主要介绍了 KMM 是什么,通过一个 demo 演示 KMM 跨平台复用代码的能力,包括网络请求、解析和数据缓存等,目前开源社区还不够完善,仅能满足基础功能,不过有 Android Jetpack 的加入,相信开源组件会越来越丰富。

    根据 KMM 的编译形式和官方介绍,可以看出 KMM 在性能上接近原生,同时 KMM 支持和原生代码互操作,KMM UI 跨平台在官方计划之中,值得期待。但是目前 KMM 在并发操作上还存在不足,在 iOS 上的协程存在性能问题,官方仍然在优化中。

    相关文章

      网友评论

          本文标题:跨平台还能怎么玩?试试 Kotlin Multiplatform

          本文链接:https://www.haomeiwen.com/subject/zzkhedtx.html