KMM探索

1,436 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情

背景

移动应用的开发维护需要兼顾Android与Ios两个系统,通常的做法是两拨人对各自平台分别开发维护,这就造成了人员的浪费,同时又有双端的体验不一致的现象,也增加了后续的维护成本,在这样的背景下许多跨平台方案应运而生,Flutter、RN相信大家已经很熟悉了,KMM又是什么东西呢,它有哪些特点呢?这篇文章就带大家分析一下。

KMM简介

Kotlin Multiplatform Mobile 是基于 Kotlin 语言进行多平台开发的一套技术框架,Kotlin Multiplatform Mobile 作为新兴起的框架,是JetBrains公司在2020年8月31日推出的基于Kotlin的跨平台框架,KMM注重的是将与平台无关的代码通用化,共用同一份Kotlin代码实现,生成两个平台的原生产物;至于平台特性相关的代码(包括UI)建议使用各自平台原生方案,各自写一份代码解决。

原理

KMM是基于 Kotlin 语言进行多平台开发的一套技术框架,它和 Kotlin Native(简称 KN)有一定联系,但 KMM 主要面向移动端开发,即:Android、iOS、Web,而 KN 则主要面向 Linux、macOS、Windows 等

当然,KMM 在 iOS 平台的实现,离不开 KN,Kotlin代码最终会在 iOS 工程中生成一套 Framework 库,可供 Objective-C、Swift 进行调用

KMM 宗旨是使用 Kotlin 语言和技术栈,开发一套可以在多平台之间共享的代码库,用来构建统一的代码逻辑,而不用针对各个平台都去实现自己的一套,从而导致人力的浪费

版本要求

Android Studio – version 4.2 or higher.

Xcode –version 11.3 or higher.

Gradle-越高越好

Jdk 8以上

image.png

接入成本

android:如图下所示,kmm目录虽然结构跟通常不一样,但他其实也是一个标准的gradle子库,所以引入方式跟以前一样直接引入,

image.png

但是这样源码依赖引入需要升级对应的gradle与构建插件,如果项目很老很乱,成本会难以估量,

可也以通过gradle的build打包成aar,这样影响会小很多。

ios:由于 KMM 模块在 iOS 平台是以 Apple Framework 的形式来具体体现的,所以 iOS 工程最主要的就是『编译』和『引入』KMM 模块生成的 Framework如何让 iOS 工程引入一个外部的 Framework?首先肯定是需要有一个真正的 Framework!所以,需要首先在上面的 Android 工程中,执行 KMM 模块的 Framework 构建切换到 Android 工程根目录,执行如下命令:

./gradlew kmm:packForXcode 成功完成构建以后,Framework 就生成了,目录在 KMM 模块下的 build/xcode-frameworks/ 目录下

优点

1.性能

由于KMM会根据不同的平台编译成不同的产物(android为aar,ios为 Framework 库),所以性能跟原生一致,也可以说就是原生。

2.健壮

简单来说就是通过IDE的提示来避免调用null的对象,从而避免了NullPointerException,在androidx里就有通过一个@NonNull的注解就可以标记变量是否为空,然后IDE会帮助检查。到了Kotlin这里就有了语言级别的支持,IDE的提示级别从警告变成了错误,拒绝编译。

3.语法糖 内联 单例

4.协程

缺陷

KMM各平台差异比较大,对ios支持不太好,依赖根据平台分为三类,分别是 Common 依赖、Android 依赖、iOS 依赖,其中Common 依赖顾明思议,是用于通用逻辑的,这种依赖只能使用基于最标准的 Kotlin 底层能力(不可以耦合 JVM、JS)构建,例如,在 Android 端上比较常用的 OkHTTP、GSON、Glide,在 iOS 上比较常用的 AFNetworking、YYModel 之类的库,都不能直接用在 KMM 模块的 Common 代码库中
通用库:

官方 JSON 解析库:github.com/Kotlin/kotl…

HTTP 请求库:github.com/ktorio/ktor

SQLite 操作库:github.com/cashapp/sql…

使用中遇到的问题:

  1. sqldelight 在js中用sql.js实现 不能持久化 ->导入lowDb,用js(“””js代码”””)实现 
  2. Js的成员变量问题 ->声明顶层常量为一段js代码
  3. 正则表达式\转译匹配不到问题 ->用三个双引号声明字符串,就不用反斜杠转译了
  4. Ktor 参数中有逗号导致参数丢失->用post请求,body自己转成Bytearray
  5. Ktor 的联网方法必须在协程中调用,并且不能以流的形式接收->转String
  6. @serialization不能序列化-> id(“kotlinx-serialization”)所有非基本类型都要@serialization
  7. npm install的包会创建替身导致找不到->yarn add的方式 但是每次编译的产物需要重新add
  8. Ios跨线程变量分享不了->标记@ThreadLocal用channel发送到同一线程修改
  9. 安卓@Synchronized iOS freeze()实现跨线程共享
  10. ios Object单例关键字失效->ios端自己控制单例
  11. embedAndSignAppleFrameworkForXcode Task找不到->kotlin版本太低升到1.5.20
  12. iOS js java调用时参数默认值丢失
  13. 导出的js方法不支持Char Long .  List Map 和所有其他非基本类型
  14. Suspend刮起方法只有在安卓的协程中可以调用,但是js可以用Promise
  15. 修改的代码三端都要跑一遍,没有hot load,调试时间拉长
  16. 网络搜索解决方案几乎全是jvm的kotlin相关答案,对ios跟js很不友好
  17. runblocking 只有安卓能用,ios也可以通过org.jetbrains.kotlinx:kotlinx-coroutines-core-native引入 但是js没有相关方法可以保证协程运行顺序
  18. ktor的js版本不支持子范型,会解析失败

学习文档

KMM 入门(一)简介与基本环境搭建

KMM 入门(二)在现有工程中集成 KMM

KMM 入门(三)平台差异化实现

KMM 入门(四)与依赖库交互

KMM 入门(五)处理多线程

KMM 入门(六)使用 SQLDelight 操作数据库