Android跨平台动态化系列(一)-现状与计划

2,956 阅读14分钟

前言

       最近看了张绍文老师(微信的高级工程师,Tinker负责人)在极客时间上面开的《Android开发高手课》这个专栏,在这个专栏中介绍了android开发的一些现状,当然还有微信这些年是如何一步一步进化的,让我深有感触。所以我萌生了去学习Android跨平台动态化这个系列,并在学习过程中想以博客的形式记录。这是这个系列的第一篇文章,我打算主要介绍一下跨平台动态化技术的一下现状,和我对这个系列学习的一种展望。

       首先跨平台和动态化是两个不同的维度,这两个维度有重合的地方也有不重合的地方,这里我会对两个维度进行解刨。

一 跨平台

       近几年来“大前端”这个概念很火,标志性的事件就有,从2017年开始,GMTC“移动技术大会”就更名为“大前端技术大会”。从现在看来,前端开发和Native开发并没有谁取代谁,而是正在融合,融合之后的产物就是所谓的“大前端”。在跨平台这个维度,我把现在的技术路线大概分成4类,他们分别是:移动web技术虚拟运行环境小程序和现在很火的Flutter

1.1 web

       从桌面时代开始,以浏览器为载体的Web技术就具备跨平台、动态更新、扩展性强等优点。随着移动设备性能的增强,Web 页面的性能也逐渐变得可以接受。客户端中出现越来越多的内嵌 Web 页面,很多应用也会把一些功能模块改为Web实现。

       一个Web页面是由HTML + CSS + JavaScript组成,通过浏览器内核执行并渲染成开发者预期的界面。浏览器的的内核主要包括两大部分,一部分是浏览器引擎:主要是负责处理HTML和CSS,遵循的是W3C标准,另一部分是JavaScript引擎:主要负责处理JS,遵照的是ECMAScript标准

       先前随着微软的Edge宣布将内核切换成Chromium,目前这个战场主要就剩下苹果Google两个玩家,它们的浏览器引擎分别是WebkitBlink(其实Blink也是fork自Webkit),JS引擎分别是JavaScriptCoreV8。对于浏览器的渲染流程,大概就如下。HTMLCSSJS以及页面用到的一些其他资源(图片、视频、字体等)都需要从网络下载。而HTML会被解析成DOM,CSS会被解析成CSSOM,JS会由JS引擎执行,最后整合DOM和CSSOM之后合成为一棵Render Tree

       web这种跨平台的方案是最常见的跨平台方案,这里我先不介绍这么多,等后面专门分析这一块的时候再详细介绍。

1.2 虚拟运行环境

       这种跨平台的方案,代表的就有阿里的WeexFacebook的React Native,当然我举得Flutter也是属于这一类,这里暂且分开。基于 WebView的H5跨平台方案,就算经过近乎疯狂的性能优化,但是对于一些交互和动画复杂的场景(例如左右滑屏、手势),性能还是无法满足要求。

       Facebook在2015年开源了React Native,它抛弃了WebView,利用JavaScriptCore来做桥接,将JavaScript调用转为Native调用。也就是说,React Native最终会生成对应的自定义原生控件,走的是系统原生的渲染流程。虽然React NativeWeex向上对接了前端生态,向下对接了原生渲染,看起来是非常完美的方案。但是前端和客户端,客户端中的AndroidiOS,它们的差异并不那么容易抹平,强行融合就会遇到各种各样的坑。

       这种方案是一种中庸的方案里面的坑还是很多的,Weex现如今已经被阿里给放弃了,但是Facebook还在对此方案进行优化,当然在国内像美团就对React Native进行了改动形成了自己的一套框架MRN,这个方案暂且就介绍达到这里,后面专门的文章再来分析。

1.3 小程序

       2017年初,张小龙宣布微信小程序诞生。如今小程序已经走过了两年,在这两年间,小程序的生态也在健康的发展。在此基础上每个大厂都纷纷推出了自己的小程序框架,例如有微信厂商支付宝今日头条百度淘宝Google Play

       小程序并不属于一种跨平台开发方案,从技术上看,小程序的框架技术是开放的,可以采用 H5 方案,也可以采用 React Native 和 Weex,甚至是 Flutter。下面用张图来表示这几种小程序的区别,如图:

       这里除了独树一帜的快应用,其他小程序的技术方案基本都跟随了微信。但是考虑到H5在一些场景的性能问题,利用浏览器内核提供的同层渲染能力,在 WebView之上支持一些原生的控件。如果哪一天微信小程序支持了所有的原生控件,那也就成为了另外一套React Native/Weex方案。支付宝和百度小程序等之所以和微信的技术方案相同的原因就是,他们也希望已有的微信小程序能够快速的迁移到自己的平台。

1.4 Flutter

       Flutter的早期开发者Eric Seidel曾经参加过一个访谈What is Flutter,在这个访谈中他谈到了当初为什么开发Flutter,以及Flutter的一些设计原则和方向。Eric Seidel和Flutter早期的几位开发人员都是来自Chrome团队,他们在排版和渲染方面具有非常丰富的经验。那为什么要去开发 Flutter?一直以来他们都为浏览器的性能而感到沮丧,有一天他们决定跳出Web的范畴,在Chromium 基础上通过删除大量的代码,抛弃Web的兼容性,竟然发现性能是之前的20倍。所以他们的设计原则分别是,性能至上效率至上

  • 性能至上: 内置布局和渲染引擎,使用Skia通过GPU做光栅化。选择Dart语言作为开发语言,在发布正式版本时使用AOT编译,不再需要通过解析器解释执行或者JIT。并且支持Tree Shaking无用代码删除,减少发布包的体积。
  • 效率至上: 在开发阶段支持代码的Hot Reload,实现秒级编译更新。重视开发工具链,从开发调试测试、性能分析都有完善的工具。内置Runtime实现真正的跨平台,一套代码可以同时生成 Android/iOS 应用,降低开发成本。

       Flutter是从浏览器引擎简化而来,无论是它的布局引擎(例如也是使用CSS Flexbox 布局),还是渲染流水线的设计,都跟浏览器都有很多相似之处。但是它抛弃了浏览器沉重的历史包袱和 Web 的兼容性,实现了在保持性能的前提下实现跨平台开发。Flutter在跨平台和性能上都有很大的优势,但是在动态性上就很有限,没有其他的方案好。

二 动态化

2.1 常见的动态化方案

       移动端动态化方案在最近几年一直是大家关注的重点,虽然它已经发展了很多年,但是每年都会有新的变化,这里我们先来看看各大公司有哪些已知的动态化方案。

       我在观看2018年QCON大会时看到,美团工程师分享了他们的动态化实践。美团作为一个强运营的应用,对动态化有非常强烈的诉求,也有着非常丰富的实践经验,他们将动态化方案分为下面四种类型。

  • Web容器增强:基于H5实现,但是还有离线包等各种优化手段加持,代表方案有PWA、腾讯的VasSonic、淘宝的Zcache以及大部分的小程序方案。
  • 虚拟运行环境:使用独立的虚拟机运行,但最终使用原生控件渲染,代表方案有React NativeWeex快应用等。
  • 业务插件化:基于Native 的组件化开发,这种方式在淘宝、支付宝、美团、滴滴、360 等航母应用上十分常见。代表方案有阿里的Atlas、360的RePlugin、滴滴的VirtualAPK等。除此之外,我认为各个热修复框架应该也属于业务插件化的一种类型,例如微信的Tinker、美团的Robust、阿里的AndFix
  • 布局动态化:插件化或者热修复虽然可以做到页面布局和数据的动态修改,但是代价巨大,而且也不容易实现个性化运营。为了实现 “千人千面” ,淘宝和美团的首页结构都可以通过动态配置更新。代表的方案有阿里的Tangram、Facebook的Yoga

2.2 动态化方案的选择

       四大动态化方案哪家强,这里先用一张图看看他们的区别,如下:

       目前我们还无法找到一种“十全十美”的动态化方案,每种方案都有自己的优缺点和对应的使用场景。比如Web容器增强方案在动态化能力、开发效率上有着非常大的优势,但在稳定性和流畅度却差强人意。恰恰相反,布局动态化方案在性能上面有非常不错的表现,但是在动态化能力和开发效率上面却受到不少限制。

       Web容器增强和虚拟运行环境方案通过独立的Runtime和 JS-SDK来桥接Native模块,而业务插件化则通过插件化框架和接口能力直接调用。相比之下前者更加抽象而不易造成代码混乱,这也是目前各大公司逐渐开始“去插件化”的原因。

2.3 Native动态化方案

       Native动态化方案主要分为热修复、插件化布局动态化两种。

2.3.1 热修复和插件化

       曾经微信希望使用 Tinker 来代替版本发布,在热修复的基础上实现四大组件的代理。但是 Android P 私有 API 限制的出现,基本打消了这个念头。热修复不能代替版本发布,但是我们可以通过它来实现一些应用商店不支持的功能,例如精准的灰度人数控制、渠道和用户属性选择、整包的 A/B 测试等。

       在Android P在中国有非常多的应用出现了兼容性问题,其中大部分是热修复、插件化以及加固等原因造成的(Google 提供的数据是43%的兼容性问题由这三个问题造成)。在此基础上,热更新和插件化的未来是悲观的。但是Android Q的发布给了一个很大的惊喜。Google在Android P新增了AppComponentFactory API,并且在Android Q增加了替换Classloader的接口instantiateClassloader。在Android Q以后,我们才可以实现在运行时替换已经存在ClassLoader和四大组件。这样子就可以使用Google官方API就可以实现热修复,这样以后Android版本再升级也不用担惊受怕了。

       热修复和插件化作为 Native 动态化方案,它们有一定的局限性。随着移动技术的发展,部分功能可能会被替换成小程序等其他动态化方案。但是从目前来看,它们依然有非常大的存在价值和使用场景。

2.3.2 布局动态化

       像淘宝、美团首页这些场景,我们对性能要求非常高,这里只能使用Native实现。但是首页也是流量的聚集地,“提增长、提留存、提转化” 都要求我们有强大的运营能力。最近两年,淘宝、天猫一直推行 “千人千面”,每个用户看到的主页布局、内容可能都不太一样。布局动态化正是在这个背景之下应运而生,在我看来,布局动态化需要具备下面三个能力。

  • UI容器化:能够动态地新增、调整UI界面而无需发版。
  • 能力接口化:点击、跳转等通用能力可以通过路由协议对外提供,满足UI容器化后的调用需求。
  • 数据通道化:数据上报也可以通过字段配置,实现客户端根据配置自动上报。

       在具体的实践上,可以选择天猫开源的Tangram,也可以基于底层的VirtualView做二次开发。

       总的来说,布局动态化相比虚拟运行环境来说,它不仅实现了 UI的动态新增和修改,也有着良好的体验和性能,同时接入和学习成本也比较低。

三 总结与计划

       本篇文章体现出来的技术很广,内容很多,在性能、跨平台、动态性这个铁三角中,我们不能同时将三个都做到最优。

       H5的跨平台方案只要投入不太高的开发成本,就能开发出性能、功能还不错的应用。但是如果想做到极致优化,很容易发现开发者可控的东西实在比较少,性能和功能都依赖浏览器的支持。这个时候如果想走得更远,我们不仅需要了解浏览器的内部机制,可能还需要具备定制、修改浏览器内核的能力,这也是阿里、腾讯、头条和百度都要组建内核团队的原因。

       原生开发则相反,刚开始要投入很高的开发成本,但是一旦开始有产出之后,开发者能够有更的发挥空间,而React Native和Weex方案更是希望打造兼顾跨平台、开发成本以及性能的全方位解决方案。

       从目前来看,每一种方案都有着自己的使用场景,无论是 React Natve 还是 H5,都无法完全取代 Native 开发。

       在本系列后面的文章中我将围绕这个上面的每种跨平台动态化方案进行学习和记录,我的最主要的目的是去了解其原理,在此过程中我打算会分析有些方案的代表开源库,希望以此来提升自己的能力。这只是一个开始,期待下一次分享。

参考资料

  • 《Android开发高手课》
  • 《美团客户端动态化实践》