更多深度文章,请访问云计算频道:https://yq.aliyun.com/cloud
2017年1月12日,在WEEKONF 2017上,阿里巴巴事业部无线牛倩团队以阿里巴巴无限业务的实际业务,分享了牛倩开业一周的应用实践。本文分享了业务面临的挑战,无线牛倩团队如何一步步转向WEEK,以及在实际过程中遇到的挑战和做出的努力。本文是Weex在牛倩公开赛应用实践的分享和整理。
本文整理自演讲嘉宾的分享视频和PPT。
本次分享将主要介绍Weex在牛倩开放平台的一些应用实践。今天分享的内容主要分为以下四个部分:
接下来解释插件的应用场景。牛倩是一个数据驱动的平台。当淘宝里一个交易订单的数据发生变化时,系统会收到一条消息,这条消息会推送到牛倩的客户端,然后客户端的数字区域就会发生变化。当用户发现客户端上的号码有变化或者收到新消息时,可以通过点击号码或者消息跳转到isv的插件,然后插件完成isv提供给用户的一些具体任务,比如查看订单的具体细节,复制订单的具体发货地址,修改商品价格等。这些功能都是在isv提供的插件内部完成的。插件完成业务处理后,会跳回牛倩的模块,比如像旺旺这样的接收或通信,接收后再跳转到isv的插件继续处理。对于用户来说,看到的是牛倩客户端的整体操作流程,但在牛倩内部,其实是从牛倩跳到isv的插件应用,再跳回牛倩的三步动作。所以isv提供的插件的稳定性和用户体验的一致性将是一个需要我们关注的问题。
那么我们为什么选择Weex呢?其实在接入Weex之前,我们也在React Native上进行了一些尝试。React原生方案提出后,我们觉得很好,可以很大程度上解决我们当时开发方式带来的问题。因此,2015年11月,我们开始试用自己的业务代码,经过验证,发现在长列表加载速度等问题上可以满足要求,于是2016年3月,我们开始尝试将其打包,提供给isv。但是在开发和接入的过程中不断暴露出问题,最后不得不切换跑道,投入Weex的怀抱。
接下来说一下我们在React Native遇到的问题。首先是性能问题。随着业务的日益复杂,捆绑包的大小会成为更大的问题,捆绑包会不断膨胀,需要下大力气优化。更可怕的是,捆绑包的大小会直接影响加载速度。我们做过一个对比实验:当业务足够复杂,捆绑包足够大时,首次加载时间甚至比一个Webview还要长。另外就是React Native自身的问题,比如核心组件Listview中的单元格重用,会影响内存开销和性能。当然,这些问题在今天看来可能有一些解决的办法,但对当时的我们来说确实是一个巨大的挑战。
第三个问题是结尾的不同。React Native强调的是一次学习而不是一次编写,所以意味着isv无法关心平台上的差异,消除平台上差异的工作只能由平台自己来处理,但这些问题并不是不可克服的。最后让我们放弃React Native的是它的破改问题,因为React Native是一个开发速度很快,更新频率很高的框架。在我们接入的阶段,React Native基本上一到两个星期就会更新一次,两次更新之后就会出现一个破变问题,这给我们带来了很大的挑战。因为如果你只使用React Native开发自己的业务,可能不会有太大的问题,但是如果你使用React Native为其他ISV搭建平台,那么破改的问题就会让开发者非常头疼。如果每一次改动都需要通知平台所有ISV进行版本更新或升级,成本将难以承受。
基于以上原因,Weex走进了我们的视野。Weex吸引我们的有以下几点:第一,版本升级的前向兼容性,Weex团队承诺框架的前向兼容性。第二点是Weex具有多终端一致性,我们不需要自己处理多终端一致性问题。Weex的第三个优点是轻量级,支持可插拔能力,扩展方便。Weex提供了基本的功能,但是这些功能可能无法满足每个业务场景。而且像牛倩这种面向业务的业务场景,我们需要对自己有更多的业务考虑,所以我们非常重视这个框架是否可以轻松替换,是否可以提供基础能力和扩展能力,Weex在这方面做得非常好。另一方面,Weex解决了React Native本身的一些性能问题,比如Bundle运行环境的共享,Listview的复用也得到很好的解决。最后,Weex可以灵活支持多种前端框架,无需切换前端框架,因为我们之前在React Native上做了很多工作,如果不能实现平滑过渡,会给我们带来很多麻烦,而Weex可以帮助我们平滑迁移。
这样就产生了下图所示的框架。客户端的基本分层并没有改变。此外,容器层还加入了web容器,做了一些相关的工作打通容器,比如使Weex容器中原本为ISV开放的Web容器无缝使用成为可能。这种Web容器可以被视为导航页面或组件。此外,它为新的开发方法提供了一些新的框架,如包管理的相关机制,并提供了更原生的存储机制、数据收集、导航管理和插件生命周期管理等。此外,我们还提供一整套与开发相关的工程管理工具。工程管理工具的目的主要是在安装、打包、发布的一系列过程中遵守包的规范和格式,同时也为isv提供一些开发和调试工具。
对于资源加载,在QAP1.0中,我们为ISV提供了将网络请求与本地资源相链接的能力。插件容器发起请求时,传统的方式是直接向isv的云端请求资源,而QAP1.0中提供了离线包的机制,插件容器可以先请求离线资源包,看看资源包中是否有需要的资源,然后通过牛倩的云端将相关资源分发给客户端 也就是QAP1.0的资源加载机制,QAP2.0版本彻底废除了插件容器直接向isv请求资源的链接,只有在服务降级的情况下才有可能使用这个链接。 因此,新的开发方法对包管理的要求非常严格。以前资源包可能是可选的,因为确实无法通过网络请求资源。但QAP2.0将资源包升级为应用程序,成为插件容器请求资源的主战场。相比之前资源包中JS或CSS之类的静态资源,QAP2.0版本的资源包中有很多配置文件,可以对资源配置安装包的特定能力或动作。
说完了资源加载,我们来说说数据请求。说到数据请求,先说说isv在之前开发过程中遇到的问题。为了完成一项业务,一个isv实际上需要调用多个API来获得想要的结果。另外,为了保证数据的时效性,需要经常拉取。因为不知道数据什么时候更新,每次都需要拉取,导致缓存利用率低。另外,在之前的架构中,缓存需要考虑用户隔离、大小限制等问题,使用起来会变得非常麻烦。
在QAP2.0中,我们引入了批量顶请求,即批量发送和接收多个请求。另外,对于数据推送,TCP长连接中有一个数据推送通道,在QAP2.0中开放给isv,isv可以实时将其重要数据推送到客户端,不用每次都去拉想要的数据。而且实现了多用户数据的自然隔离,提供了批量存储接口。
在页面渲染部分,我们做的工作相对较少,主要是给予其他团队支持。QAP1.0用的是MSUI+Webview,QAP2.0用的是NukeUI+Weex,这里稍微说一下NukeUI的优势。NukeUI有更规范的UI交互,提供了千牛组件开发的规范,以及主题换肤能力和更好的性能。
在做了这些事情之后,在推出组件和包装QAP时仍然存在许多问题。其中之一是包装的大小。目前牛倩平台上的插件功能很多,非常复杂。isv开发的页面不像运营页面,可以看作是由多个页面组成的APP的一个程序,所以包大小很难控制。另外,每个千牛用户平均有20多个插件,插件安装包也很多。如果套餐大小控制不好,会对用户的流量和空造成巨大的消耗。捆绑包的大小也会在一定程度上影响插件的性能。捆绑包主要包括像rax、components、SDK这样的几个部分,所以我们可以看到对于每个包,都有很多公共部分。虽然rax是按需打包的,但是随着业务越来越复杂,一个APP几乎可以覆盖组件库中的所有组件,所以可以把这部分提取出来作为通用部分。
在开发工具方面,我们提供了QAP的CLI,可以实现创建项目、导入样例项目、调试、打包上传、安装真机测试、获取最新测试包等功能。但是在给isv提供CLI的时候发现了一些问题,比如平台环境的问题,安装慢的问题。
针对以上问题,我们现在做的就是把整套相关依赖做成IDE,让开发者在IDE中一站式完成,找到入口,创建项目,调试项目,一键安装上传。