一、老项目现状及痛点
1.1 现状
项目是一款目的地旅游场景下的APP,包括Android和iOS平台。项目从2023年2月开始,为了节约成本,快速迭代开发,经过一周的技术选型和调研,依然决定采用混合式开发框架。
技术栈
java、kotlin、objective-C、mpaas、uniapp、vue3、gradle、CocoaPods、Shell、Node、gitlab-running
iOS
主项目使用objective-C代码搭建宿主应用,接入阿里云移动端mPaaS框架。部分要求性能较高的采用原生代码开发,如主界面、登录注册、Push、支付、第三方登录、IM等。
Android
主项目使用java和kotlin代码搭建宿主应用,同iOS平台一样,接入阿里云移动端mPaaS框架。
mPaaS
除了主界面Tab和部分性能要求高的页面外,其他所有页面均使用mPaaS框架进行展示。主要使用mPaaS离线包和mPaaS小程序。其特点是用Vue3进行小程序包页面开发,打包后上传mPaaS后台进行管理,在移动端启动后进行拉取和展示。
uniapp
uniapp具有快速框架搭建,一键生成H5和小程序的能力(生成APP的话性能上和无感更新上满足不了诉求)。uniapp主要用在离线包开发,把业务拆分成小模块生成对应的离线包资源,通过mPaaS提供给APP进行运行。
vue3
开发页面主要使用vue3技术栈,用uniapp搭建框架后,可直接生成微信小程序。
其他
gradle、CocoaPods、Shell、Node、gitlab-running主要用在项目工程化中的构建自动化运行。
1.2 痛点
代码逻辑重复
在APP原生开发过程中,每次在iOS开发完的功能逻辑在Android端也要实现一遍,很多像网络数据获取、业务逻辑处理、交互界面都是重复的,感觉有写两遍的冗余感。另外,每次改Bug都会在同样的位置不同端修改2遍,费心费力,开发时间上也是成倍的增加。
H5页面性能瓶颈
H5虽然用vue3开发,但运行逻辑底层还是js实现,其核心还是单线程解析式运行,效率上和多线程应用还是有差距的,特别是在业务逻辑较大,交互复杂的情况下,性能瓶颈问题特别突出。
动画效果
在原生开发中,有一些动画表现亮眼,特别提高用户的使用体验。而用H5开发后,复杂的动画效果无法做到,像原生开发中有的共享元素动画,在H5中实现起来很复杂。
权限
原生开发申请权限后,下次就不会弹出权限申请。而H5开发中,实现录音功能,每次都弹出申请录音权限的弹框,特别影响APP体验,还要借助jsApi进行桥接实现部分功能。
二、改造思路及方案
2.1 改造思路
Flutter
考虑过重新用Flutter进行实现,但需要重写所有功能,并且需要团队具有Dart开发经验,并且对于特殊功能依然要实现Fluuter原生插件,工作量上无法接受。
KMP
kmp支持业务逻辑跨平台、cmp支持UI跨平台、也都支持原生间相互调用,这样就可以做到渐进式改造老项目。并且相对于Dart,Kotlin更容易上手,因为Android开发本来就用Kotlin,加上使用Jetpack Compose原因会更容易理解。对于原来移动端开发来说,无论使用Jetpack Compose还是swift UI都更容易转移到Compose Multiplatform上,他们同样是声明式代码结构,同vue3、Flutter都有相似之处。
2.2 改造方案
新功能
新功能直接创建KMP项目进行开发,开发完成后执行gradle命令生成Android平台的.aar和iOS平台的framework文件,导出的文件可以直接用在老项目中(目前已代码验证可行)。
老功能
老功能采用先逻辑后界面的原则,先把业务逻辑和网络请求及数据迁移到KMP项目的shared共享库中,提供给原生界面使用。而后在KMP项目的composeApp中开发UI界面逐步替代老项目对应模块。
三、当前进展及下一步计划
3.1 当前进展
目前KMP项目已开发了首页的全部功能,并且作为依赖已接入Android和iOS的老项目运行,运行状态良好。
当前为了验证可行性,所有的界面和逻辑都放在composeApp的commonMain目录下。
3.2 下一步计划
-
迁移非UI业务逻辑代码到shared目录,为非界面跨端共享做准备。
-
用kmp重写老项目非核心支持模块(城市选择器、时间选择器)并接入。
四、遇到的问题及思考
-
用compose在kmp项目中写的界面,可以在纯原生项目中任意引用吗?
本人只验证引用kmp项目首页,还没有验证随意引用某个页面,后续验证后专门写一篇分享。
-
原生Jetpack Compose和swiftUI对引用kmp页面的复杂度怎么样?
本人通过iOS的UIViewControllerRepresentable使用代码```MainViewControllerKt.MainViewController```导入kmp页面,还是比较简单的,相对swiftUI直接调用多了一步包装。在Android方面,由于都是kotlin写的,代码之间调用随意。