作者;京东科技 胡大海
前言
动态化-罗码(后文统称动态化)是一个全自主研发的一站式跨平台解决方案,一份代码,可以在iOS、Android、H5及华为HarmonyOS运行。在研发团队使用后可大幅降低研发人力成本;为业务提供实时触达、A/B触达等能力以提升业务投放效率;同时保障了C端用户优秀的用户体验。
一、背景
市面上的APP,一般使用两种技术方式承载业务:
1、原生开发方式:优势是可以充分使用系统能力,带来极致的用户体验;劣势是动态性差、发布周期长、无法跨平台。
2、H5开发方式:优势是动态性好、可随时发布、支持多平台;劣势是体验相对较差、系统能力使用受限(需要通过桥接使用系统原生能力)。

我们从业务效率、用户体验、研发成本三个维度总结以上两种技术存在的问题:
1、业务效率
公司端内业务需求一般需要集中在某一个固定时间发版,且各个应用市场对于APP的发版都有审核的周期,这样原生开发的业务就无法及时触达用户,甚至对于未升级的旧版用户无法触达。
2、用户体验
研究表明,如果一个移动端页面加载时长超过 3 秒,用户就会放弃等待;网页加载时长每增加1 秒,用户就会流失 10%,但是由于WebView本身的历史包袱,渲染性能差、JS执行效率低、用户体验差的问题一直无法彻底解决。
3、研发成本
同一个业务如果四端(H5、Android、iOS、Harmony)同时开发,需要投入四端人员,开发成本高。

二、方案实践
1、方案简介
针对上述背景中两种技术存在的问题,业界相继出现了FaceBook公司的ReactNative、阿里巴巴公司的Weex、腾讯公司的微信小程序、京东的Taro(RN原生部分)、Google公司的的Flutter、华为的ArkUI-X等各种跨端解决方案。

几乎每个跨端解决方案追求的就是在保证C端用户良好的用户体验的同时,让业务以最小的人力成本和最快的速度触达用户;下面我们从开发效率、性能、动态性、渲染方式、上手难度等维度对业界跨端方案及我们自研的动态化跨端方案做对一个对比:
框架代表 | React Native | Weex | H5 | 小程序 | Flutter | 动态化 |
---|---|---|---|---|---|---|
开发效率 | 高 | 高 | 高 | 高 | 高 | 高 |
性能 | 高 | 高 | 差 | 中 | 高 | 高 |
动态性 | 高 | 高 | 高 | 高 | 无(官方不支持) | 高 |
渲染方式 | 原生控件渲染 | 原生控件渲染 | WebView渲染 | WebView渲染 | 自绘制渲染(SKIA) | 原生控件渲染 |
核心语言 | JSX | Vue | Vue等 | 自定义DSL | Dart | Jue(类Vue的DSL) |
上手难度 | 低 | 低 | 低 | 低 | 中 | 低 |
业务包大小 | 默认单一、较大 | 较小、可多文件 | 随页面下发 | 随页面下发 | 随APP发布 | 较小、可多文件 |
通过上述表格对比发现,每一个框架都有很多优劣和部分劣势,那么为什么要自己再做一个动态化方案而不直接使用现有方案呢?
1、React Native和Weex是两个比较相似的技术方案,Weex在核心开发语言和包大小(React Native可以通过业务拆包减小包大小)相比React Native具有一定的优势,但是都存在两个共性的问题,第一对于常用的长列表渲染、瀑布流渲染都存在渲染瓶颈,第二在框架每次升级后都需要所有存量业务测试验证,造成测试成本突增、业务稳定性被破坏。
2、H5通过离线化技术能够一定程度缓解渲染速度,但在复杂场景交互仍然存在较多交互问题,甚至在运营商被劫持、Cookie丢失等场景会导致页面直接白屏。
3、小程序可以看做是一个特殊的H5技术,它使用了双线程模型将UI渲染和业务逻辑分散到两个线程执行。
4、Flutter的Dart开发语言相比其他框架学习门槛较高,并且因为没有动态更新能力,无法满足业务热更新的诉求,虽然可以通过一定的技术手段达到动态发布的目的,但整个链路就会变得复杂,导致业务维护、排查问题成本直线上升。
每一个框架都有很多先进理念值得我们学习,站在巨人的肩膀上,我们吸取了各个框架的优势,加上自主创新,发明了卡片级动态化渲染技术、高性能列表技术、底层框架升级业务无感技术、业务天然分包技术、多端分布式实时预览等一系创新,打造了自主可控的动态化跨端解决方案。
2、实现方案
2.1、源代码
分为JSEngine和业务代码(Hello.jue)两个部分,JSEngine即为我们自主研发的业务代码运行时环境,在产物运行阶段会第一时间被加载,负责业务代码实例管理、任务管理、虚拟Dom树管理、虚拟Dom树Differ、业务页面渲染管理、生命周期管理、事件分发、业务逻辑处理等一系列功能;业务代码即具体的业务代码,其结构和Vue一致,包含了描述业务UI的template、业务逻辑表达的script以及业务UI样式的style三个部分,语法和Vue几乎一致,但是具备了标签扩展能力,比如在长列表和瀑布流场景我们可以通过结合原生列表及瀑布流控件快速打造出一个高性能的列表标签。
2.2、脚手架
脚手架方便开发者进行项目工程化管理,通过我们自研的complier loader完成业务代码及JSEngine的编译工作,借助Babel插件支持了ES6语法,支持图片Base64转换、产物Zip压缩、热重载等一系列能力;为保障业务构建产物安全,目前脚手架构建能力已经以云端构建方式运行,提供了统一的构建环境。
2.3、产物管理
云端构建的产物,可以直接发布到动态化资源管理后台,后台提供了资源加密、灰度发布、长连接推送等强大的管理能力,满足了业务人群灰度、AB发布等诉求,为业务快速试错提供了有力保障。
2.4、产物运行
这里分为两种类型产物的运行,首先是JSEngine,在iOS系统使用系统提供的JSCore、在安卓系统使用V8引擎、在Web使用浏览器的WebKit,由一个专门的JS线程在一个最早的时机(比如APP启动)进行JSEngine的加载,加载完毕后,就形成了了业务产物运行的环境;然后客户端通过下载后台对应的产物,经过解密及解压缩后就得到了业务原始JS文件,业务资源的运行过程,是一个创建业务实例的过程,由JSEngine统一管理。
2.5、统一接口声明
JSEngine统一创建业务实例的过程是统一的,而真正渲染的客户端是多个(iOS、Android、H5、HarmonyOS等),通过制定统一的接口规范客户端标准化对接及扩展(比如在华为鸿蒙系统适配只需实现统一接口即可),接口包含了实例创建声明周期、元素的增删改查、JS和原生的双向通讯、热重载交互等各种能力。
2.6、接口实现
这个过程的核心任务是在iOS、Android等系统上,实现统一接口声明的方法,创建出业务对应的页面和处理业务交互逻辑。通过完成统一接口的元素增删改操作及其他指令后就构建出了一个组件树,再经过布局引擎布局后,就显示出了业务具体的页面效果;当用户在业务页面发生了交互事件后,通过统一接口的JS和原生的双向通讯调用到业务方,当业务方需要改变UI布局的时候,同样通过JS和原生的双向通讯触发布局引擎重新布局,由于JS语言本身是图灵完备的,所以任何业务逻辑都可以在JS中实现而不会收到任何限制;这样就完成了业务UI渲染和交互逻辑的处理过程。
三、应用场景
1、卡片场景
动态化项目孵化于京东金融APP实际业务场景,京东金融APP的积木式构建页面的技术,一定程度上能够根据接口数据驱动预埋在客户端的积木卡片自由组合一个页面,但是存量积木卡片修改及新增依然需要发版。当时通过调研发现,市面上的跨端技术多以页面维度进行支持,对于局部卡片模式的跨端没有很好的解决方案,我们决定自研一个能够和原生卡片共存的区域卡片动态化技术,目标如下图所示,被放大的两个卡片使用动态化技术实现,不改变其余楼层的原生实现方式。

区域动态化技术是我们自研的一套跨平台、动态化的楼层卡片解决方案,渲染速度几乎可以和原生同步,用户体验好,并无缝对接了公司内部运营系统及埋点曝光等功能。
2、页面场景
页面动态化技术是在区域动态化基础上的进一步扩展,提供了页面常用的列表组件、瀑布流组件、下拉刷新组件等,进一步提供的混合路由模块和以及沉浸式导航能力使动态化形成了区域到页面级别的升级。对于业界跨端方案普遍面临的埋点、曝光难题,我们设计实现了一套无侵入自动化埋点和曝光的协议接口,并在金融APP无缝对接了埋点、曝光通道。
3、未来适用的场景
通过进一步扩展APP级基础能力,可用于一个完整APP的开发。
四、未来规划
在渲染性能方向,探索抽取Flutter底层SKIA渲染引擎作为动态化的渲染引擎,进一步提升渲染速度和渲染一致性,降低未来多端长期维护成本。
在DSL支持方向,基于Vue3的虚拟Dom接口分离设计,以及ReactNative最新的渲染流程架构设计,为虚拟Dom技术思想打造的跨端框架对接多个前端DSL提供了空间,未来Vue3和React开发的项目可以结合动态化实现跨端,充分发挥动态化原生渲染优势,使前端业务低成本享受原生丝滑体验。
五、写在最后
动态化是一个涉及JavaScript、iOS、Android、Java、Harmony、Vue、Node、Webpack等众多领域的综合解决方案,我们有各个领域优秀的小伙伴共同前行,大家如果想深入了解某个领域的具体实现,千万别忘了点赞+收藏,方便以后随时阅读和提出宝贵意见。