前言
客户端现状
工作中,经常遇到产品想尽快上线看数,CR业务也总是倒排期状态,native 的发版窗口是他们经常要关注的,往往因为窗口时间问题,导致某个需求业务迭代周期长,客户端开发在业务动态化方面多有被动。由于线上升级不存在强制升级,老版本占比依然在 5%到10%之间,用户无法及时体验到最新的功能更新或Bug fix。目前端上的动态化诉求越来越多,市面上的方案也呈‘百家争鸣‘的局面。
动态化的必要性
为什么需要动态化技术呢? 客户端定期发版的方式存在一些问题,比如:
- 审核周期长, 且可能审核不通过。 周期长导致发版本不够灵活, 紧急的业务需求不能及时上线。
- 线上出现急需修复的bug时,需要较长修复周期,影响用户体验。
- 安装包过大, 动辄几十兆几百兆的应用升级可能会让用户比较抗拒。
- 即使上线了,也无法达到全部用户升级, 服务端存在兼容多版本App的问题。
面对这些问题,如果能实现app增量、无感知更新,实现功能同步。对公司还是用户是非常重要的需求,能实现app动态化更新就显得非常重要,能很好的解决以上问题:
- 随时实现功能升级,不存在应用市场长时间审核和拒绝上线问题,达到业务需求快速上线的目的。
- 线上bug可以实时修复,提高用户体验。
- 可以减小发版功能包体积,只需要替换新增功能即可。
- 功能保持一致,类似网页一样,发版后用户同步更新,不存在旧版本兼容问题。
这里简单说下目前市面上已有跨端动态化方案,在公司中也使用了Flutter,React 和千人千面,这里也算是为下一篇React学习RoadMap 做一个简单的开场和前情提要。
图片引用张绍文极客课程
跨端分类
Hybrid
移动端初期比较流行的方式,通过WebView为载体,客户端中嵌套使用 就具备跨平台、动态更新、扩展性强等优点。但是由于Web 一个页面由HTML + CSS + JavaScript组成,在客户端加载中,往往需要渲染引擎预热,资源缓存等手段进行优化,来提升Hybrid 在客户端使用体验不佳、秒开不达标等情况,不过因为自带动态化特性,互联网初期还是很多页面都是这样使用的,也是后续小程序等跨端类型的基础。
小程序
这里我们以微信小程序为主,其实可以小程序看做是Hybrid的一种,微信小程序视图渲染依然使用H5 和Webview进行渲染,逻辑层吸收了虚拟运行环境的优点,使用JavascriptCore进行桥接,两者都是独立的模块,其实就是两个线程,并不具备数据直接共享的通道。视图层和逻辑层的数据传输,要由 Native 的 JSBrigde 做中转。但小程序好在对这一模式进行了很彻底的优化,包括但不限于:分包技术,Diff视图刷新,数据预拉取,分屏渲染,非关键渲染后移,长列表优化等手段。
虚拟运行环境
目前市面上比较知名的方案有阿里的Weex、Google的Flutter和FaceBook的React Native。React Native底层利用JavaScriptCore/V8,通过系统原生的渲染流程进行渲染,Weex早期思路也是如此,但是他们都存在一个问题就是渲染强依赖 Android/iOS 的系统 UI,这样虽然可以降低实现成本,系统 UI 的性能和稳定性也是最好的,但是不同的系统 UI 的实现原理也有差异,还有双端版本碎片化问题,这也是导致此类方案坑越来越多的原因,维护成本太高。 Weex2已经优化了渲染管道部分,使用Flutter 引擎底层使用skia异步渲染。
相较于以上两种方案,Flutter可能也不太算虚拟运行环境这一分类下的,但是这里还是放在了一起。Flutter 底层也是内置的Runtime 解析器,一套Dart代码可以编译生成Android 和 iOS两套原生代码,在渲染上基于skia 通过GPU做光栅化,在发布正式版本时使用AOT编译,不再需要通过解析器解释执行或者JIT。并且支持Tree Shaking无用代码删除,减少发布包的体积等方面做出优化,目前Flutter是跨端方案中使用者最多,并且比较被看好的,但是Flutter 抛弃了Web的兼容性,虽然保持了跨端的性能,但是在动态化方面没有一点优势。
各个公司对于Flutter动态化也都有自己的方案和想法,这里主要说一下美团的方案思路,58同城的动态化方案已经开源,感兴趣的可以移步 Fair Github,美团的方案大概思路是:布局,逻辑依然都是使用Dart, 通过静态生产 DSL+Runtime 解释运行的思路,解决布局和逻辑的动态化,虽说实现了动态化,不过因为添加了一层Runtime解析层,个人认为是为了完成动态化,牺牲了性能,怎么说呢有得有失。
动态化方案
市面上包括开源的和不开源的其实每家大厂几乎都有自己的动态化方案,这里我主要归类下Native动态化和布局动态化
Native 动态化方案
Native动态化方案主要分为热修复、插件化和布局动态化两种。
热修复、插件化动态化:插件化是将一个apk根据业务功能拆分成不同的子apk,插件化更关注动态加载、热更新 热修复。 热修复更关注于修复线上bug。因为热修复和插件化,国内 Android 生态也带来一些不太好的影响,比如增加用户 ROM 体积占用、App 启动变慢 15%、OTA 首次卡顿等。Android Q 之后,动态加载的 Dex 都只使用解释模式执行,会加剧对启动性能的影响。 笨重的插件化框架不仅影响应用的启动速度,而且多团队协作的时候并没有想象得那么和谐,接口混乱、仓库不好管理、编译速度慢这些问题都会存在,其实现在很多大厂都是逐渐去插件化,阿里内部大都使用Weex 在非核心页面落地。
关于插件化和热修复原理这里不展开说了 网上也有很多不错的文章
https://juejin.cn/post/6973888932572315678 # 浅谈Android插件化
https://www.jianshu.com/p/08748b128ce3 # Android热更新技术总结
布局动态化:在淘宝、美团和饿了么首页存在很多入口的场景,强运营。首页考虑到性能问题和流量的聚集地,大多使用 Native 实现,“提增长、提留存、提转化”都要求我们有强大的运营能力,淘宝天猫也有类似的千人千面一说,动态化布局在这种场景下应运而生。以Virtualview为例,使用xml来描述布局,压缩成二进制格式,通过资源管理平台进行下发,客户端获取后解析并渲染为原生View 并商品,其他方案与Virtualview大同小异,后续有人总结这方面有三个能力:ui容器化,能力接口化,数据通道化。虽然布局动态化可以实现ui的动态新增和修改,并且有着良好的体验和性能,但是关于逻辑动态化部分能力比较差。
思考
本篇文章站在自己的角度,对市面上存在的跨端和动态化现状做了不算全面的总结,对于早期的Hybrid方案和后续Native动态化方案,到现在大厂更流行的虚拟环境运行方案,阿里的Weex思路也是如此,大多App首页使用动态化ui进行渲染,非核心页面使用Weex或者Flutter进行改造,Weex在性能和适配方面和Native还存在一定的差距,Flutter虽然性能和双端适配更好,但是动态化方面需要自己单独建设。
从目前来看每个方案都有一定的优点和缺点,没有十全十美的方案,只有是否适合自己的方案。
参考文档
小程序原理和优化
Tinker:技术的初心与坚持 张绍文
移动开发的罗曼蒂克消亡史 徐川