更深刻的句子,欢迎来到云计算频道。

摘要:2017年1月12日,在Weex Conf 2017上,阿里巴巴商家事业部无线天宇团队的武灵结合阿里巴巴无限商家的实际业务,分享了Weex在天宇开放方面的应用实践。本文分享了业务面临的各种挑战,无线天宇团队如何转向WEEX,在实际过程中遇到了挑战和努力。本文是关于Weex在天宇开放中的应用实践的共享定理。

本文整理了演讲者的共享视频和PPT。

本次分享主要介绍Weex在kilo open平台上使用的几个应用案例,今天分享的内容主要分为以下四个部分。

千索当前的业务方案和挑战

为什么选择Weex作为解决方案

基于Weex解决方案,我们还做了什么

目前,ISV正在使用改造效果的前后对比和目前进展。

首先介绍一下陈宇目前的工作场景。大家可能不熟悉天宇的客户端,但事实上,天宇是面向商家的移动客户端。天宇主要为淘宝商家提供一站式管理店铺和办公室的工作平台,下图右边的照片是天宇客户端的截图。

淘宝上的商家可以在天宇平台上进行顾客接待、管理自己的店铺、查看数据报告等,最重要的是商家可以完成与自己店铺相关的所有工具链接的支持。例如,交易管理工具和服务、商品管理交易、服务等。这些服务和管理都是由ISV在KLO平台上提供的。ISV可以根据用户的行为为用户提供多种定制服务,所以这一部分交给了ISV。这样基本上就可以建立一个天梭的整个工作平台。为了实现这一一站式工作平台,天宇提供了开放的插件体系,使ISV能够开发更丰富的工具。另外,KLOSO平台为用户画肖像,用户根据画像归纳在不同的用户域和不同的角色下。这样一来,每个用户看到的工作台都会不同而动态地变化,不同的用户会提供不同的功能。

接下来介绍插件的应用场景。天宇是淘宝交易订单数据发生变化时,系统会收到消息的数据驱动平台,这条消息会被推送到天宇的客户端,之后客户端的数字区域会发生变化。(David Assell,Northern Exposure(美国电视),Northern Exposure(美国电视))如果成功用户发现客户端上的数字发生了变化或收到了新消息,则可以单击数字或消息,转到ISV插件。然后,插件将执行ISV提供给用户的具体任务(例如查看订单详细信息)。或者,某些相关功能(如复制订单的送货地址和修改商品价格)在ISV提供的插件内执行。插件完成业务处理后,跳转到天宇的模块,进行旺盛的接待或沟通,招待完成后跳转到ISV的插件,继续处理。(大卫亚设,Northern Exposure(美国电视),成功)对用户来说,这是整个天宇客户端的操作过程,但在天宇内,这实际上是从天宇跳转到ISV的插件应用程序,以及跳转回天宇的三步动作。因此,ISV提供的插件的稳定性和用户体验的一致性都将是需要我们注意的问题。

以下是多角色多用户域的演示。通过下面两张照片可以看出,千牛的工作平台为不同用户提供的服务和界面是不同的。在所有工作台上,在所有O2O场景下,也许用户能看到的是左侧这样的图片界面,这样的界面不仅没有太多数据,还会强调更重要的工具。(阿尔伯特爱因斯坦,Northern Exposure(美国电视剧),Fracture)企业的老板更关心的可能是企业的订单数等与企业业务相关的数据。因此,根据用户域和用户角色,千牛的客户端必须动态构建。

那么,在使用Weex之前,天宇提供的是什么?事实上,我们把站台分成了四层。首先是装备能力层,即通过集装箱层开放拍照、网络、存储和定位等千牛的装备功能的能力。将这些功能公开给ISV后,通过容器层相互通信,显示ISV的业务代码和千牛的代码。再往上一步,将提供MSUI组件库和离线软件包系统。离线软件包与前面提到的资源中预先加载的软件包类似。顶层是千牛的业务能力层,它抽象出千牛能提供的所有业务能力,并以API方式输出。这使ISV能够通过API调用使用价格更改、退款、支付、往往招待等功能。

天梭面临的挑战是什么?事实上

大家都知道,在H5的开发方式下需要面对几个比较大的挑战,一个挑战是网络,网络对于isv的影响是巨大的;另外就是动画,其实isv比较难于实现一些与native相近的交互性的动画;第三个挑战就是安全问题,因为针对于一些运营商的劫持问题将会极大地困扰isv。除此之外,isv本身存在的问题也是需要面对的挑战,因为isv自身水平也是有高有低,参差不齐的,比如有一些isv能够将网络和动画问题解决得更好一些,能实现接近于native的交互式用户体验,而对于技术差一些的isv则往往不能实现。

另外一个方面的挑战就是isv的发布问题。因为isv可以对于自己的插件直接在服务器端进行发布。也就是说isv一旦入驻千牛平台,那么它的插件想更新什么就可以更新什么,如果isv在自己的插件中挂一个广告或者活动页面,即便是极大地损害了用户体验,但是平台也对其没有太大的管控力和约束能力。所以对于千牛平台而言,如何提高对于isv的管控能力也是非常大的挑战。另外就如同之前展示过的,千牛平台的动态性也是非常强的,所以需要针对于不同的用户域去展示不同的用户形态。以上这些就是千牛需要面对的挑战。

那么我们为什么选用Weex呢?其实在接入Weex之前,我们也进行了一些在React Native上面的尝试。在React Native方案提出之后,我们认为这个方案非常好,能够在很大程度上解决我们当时的开发方式所带来的问题。所以在2015年11月份的时候,我们就开始对于自身的业务代码进行试用,经过验证发现能够满足在比如长列表加载速度等问题上面的要求,所以在2016年3月份的时候就开始尝试封装起来,并且将框架提供给isv。但是在开发和接入的过程中,不断地暴露出了问题,所以最终不得不切换了跑道,投入了Weex的怀抱。

接下来和大家谈一谈我们在React Native里面遇到的问题。第一个是性能问题,随着业务的逐渐复杂,Bundle包的大小将会成为比较大的问题,而且Bundle包会不断地进行膨胀,所以需要花费大力气去进行优化。更可怕的是Bundle包的大小会直接影响加载的速度,我们曾经做过一个对比试验:当业务足够复杂,Bundle包足够大的时候,首次加载的时间甚至要比一个Webview加载的时间还要长。另外就是React Native自身的问题,比如像是核心组件Listview中的cell复用的问题将会影响内存开销以及性能。当然今天看来可能这些问题都有了一些解决方案,但是在当时对于我们而言,的确是一个巨大的挑战。

React Native的另外的一个问题就是内存消耗,因为每个插件都是独立的环境,所以需要对于实例进行频繁地创建和销毁,所以对于内存的消耗将会是巨大的。

第三个问题就是端的差异性。React Native所强调的是Learn Once而不是Write Once,所以也就是说无法让isv去关心平台上的差异,消除端差异的工作只能交给平台自己去进行处理,但是这些问题都不是不可以逾越的。而最终让我们放弃React Native的是它的Breaking Change问题,因为React Native是一个发展非常迅猛并且更新频率非常高的框架,在我们接入的那个阶段,React Native基本上一到两周就会更新一次,而两次更新基本上就会出现一次Breaking Change问题,而这个问题将会给我们带来非常大的挑战。因为如果只是使用React Native开发自己的业务,可能不会出现太大的问题,但是使用React Native来构建平台供其他的isv使用,那么Breaking Change问题将会使得开发者非常头疼。如果每次变化都需要通知平台所有的isv进行版本更新或者升级,这个成本也将会是无法承受的。

因为以上的原因,Weex走进了我们的视野。Weex吸引我们的有以下几点,首先是版本升级的向前兼容,Weex团队承诺框架的向前兼容性。第二点就是Weex具有多端的一致性,这样就不需要我们自己再去处理多端的一致性问题了。Weex的第三个优点就是轻量,并且支持能力的可插拔,而且具有便利的拓展性,Weex提供了基础的能力,但是这些能力并不一定能够满足每个业务场景。而且对于像千牛这样的面向商业的业务场景而言,需要有更多的面向自身的业务上的考量,所以这个框架是否是能够非常方便地替代,是否能提供基础的能力以及拓展能力是我们非常看重的,而Weex在这块做的非常好。另外一方面就是Weex解决了React Native自身的一些性能问题,比如Bundle运行环境的共享,Listview的复用问题也解决的非常不错。最后一方面就是Weex能够灵活地支持多种前端框架,而且不需要切换前端框架,因为我们之前在React Native上做了大量的工作,如果不能实现平滑过渡的话,对我们而言也会造成很多麻烦,而Weex却能够帮助我们平滑地进行迁移。

至于我们借助Weex做了些什么工作,其实在QAP2.0时代,我们主要在三个方向上开展工作。第一是针对插件APP打开主链路进行了优化;第二个就是针对于新的开发方式提供了更丰富的并且更适合千牛的能力;第三个则是在引入了新的框架之后,希望帮助千牛平台上的isv能够以更加友好的方式进行迁移并且尽快熟悉新的框架。

于是产生了如下图所示的框架。客户端这边的基本分层是没有发生变化的,在容器层加上了Web容器,除此之外还做了一些容器打通的相关工作,比如使得在Weex容器里面可以无缝地使用原来为isv开放的Web容器,这样的web容器既可以被当做导航页面进行处理也可以作为组件进行处理。另外就是针对于新的开发方式提供了一些新的framework,比如包管理的相关机制,并且提供了更加native方式的储存机制以及数据采集、导航、管理以及插件生命周期的管理等。除此之外,我们还提供了一套完整的与开发相关的工程管理上面的工具,工程管理工具的目的主要是在安装、打包、发布这一系列流程中遵守千牛的包规范和格式,并且也为isv提供了一些开发调试的工具。

接下来回到插件APP打开主链路优化这个话题上来。我们把主链路优化分为三个环节,分别是:资源加载、数据加载以及页面渲染。

对于资源加载而言,在QAP1.0的时候,我们提供给isv的是使用本地资源链接网络请求的能力。当插件容器发起一个请求的时候,传统的方式是直接向isv的云端去请求资源,而在QAP1.0提供了离线包的机制,插件容器可以先去请求离线资源包,看看资源包里面是否有所需要的资源,然后可以将相关的资源通过千牛的云端下发到客户端,这就是QAP1.0的资源加载机制。QAP2.0版本则完全废除了插件容器直接向isv请求资源的这条链路,而只有在服务降级时,才会有可能使用这条链路。所以新的开发方式对于包的管理的要求是非常严格的,之前资源包还可能是可有可无的,因为实在不行还可以通过网络请求资源,但是QAP2.0将资源包升级成为了应用程序,也成了插件容器请求资源的主战场,相比之前资源包里面基本都是JS或者CSS这些静态资源而言,QAP2.0版本的资源包里面还有很多配置文件,可以将具体的能力或者安装包的动作配置到资源包里面。

大家可以看一下QAP2.0中包的结构究竟是什么样子的。包主要又两部分构成,第一部分就是资源目录,另外一部分就是配置文件。

资源目录里面存放什么内容呢,其实就是每个配置的Bundle包,以及静态的资源图片以及icon这样的资源。而对于配置文件来说,也分为了三个部分,首先是APP相关的配置,存储了APP配置基础的一些信息,比如插件的AppKey、容器的相关信息、引入的NUKEUI、QAPSDK版本以及默认的应用启动页等等;另一部分就是APP的能力宣称配置,其实在数字区域的背后都是对应着一个插件,我们将数字的对应行为进行了业务上的抽象,并且提炼出不同的能力交由isv进行实现。如果isv要实现某一个业务,那么需要告诉客户端当触发某个插件的能力时将会唤起这个插件来帮助客户端执行这个工作,也就是将APP的能力进行声明,并与外部的能力路由进行对接。第三个是资源配置,当程序包安装和下发到本地的时候,就会去读取资源配置中的配置表,将资源下发到正确并且适合的位置上去,这个位置对于开发者是透明的,但是会极大地方便平台的管理。

谈完了资源加载,我们接着聊一聊数据请求。谈到数据请求,先要谈一谈isv在之前开发过程中所遇到的问题。一个isv想要完成一个业务其实需要调用多个API才能拿到想要的结果,此外为了保证数据的及时性,需要经常进行拉取。由于不知道数据什么时候更新,所以每次都需要拉取,这样的方式导致缓存的利用率比较低。并且之前的架构中缓存需要考虑用户隔离,大小的限制等问题,所以导致使用会变得非常麻烦。

接下来分享一下在QAP上提供了什么样数据请求等待优化方案。QAP获取数据并不是通过自己去获取数据的,而是通过淘宝的top平台去获取数据,所以我们做了top请求的长连接代理,使用TCP的长连接解决了HTTP的多路复用等时间上的消耗过多的问题,除此之外还使用了web浏览器自身提供的存储能力。

在QAP2.0中,我们引入了批量的top请求,也就是把多个请求进行批量发送以及批量接收。另外就是对于数据推送方面,在TCP长连接中有一个数据推送通道,在QAP2.0将这个数据通道开放给了isv,isv可以将自己的重要数据实时地推送到客户端,这样就不用每次都要去拉取想要的数据了。而且对于多用户的数据实现了天然的隔离,并且提供了批量存储的接口。

在页面渲染部分,我们做的工作相对比较少了,主要是交给其他团队提供支持。在QAP1.0阶段使用了MSUI+Webview,在QAP2.0阶段使用了NukeUI+Weex。这里稍微谈一下NukeUI的优点,NukeUI有更加规范的UI交互,并且提供了千牛组件开发的规范,还具备主题换肤能力,也提供了更优秀的性能。

在做完这些事情之后,在将组件推出并将QAP进行打包的时候还是遇到了很多问题。其中一个就是包大小的问题。目前千牛平台上的插件功能多并且非常复杂,isv开发后的页面不像是运营页面那样,而是可以视作APP的由多个页面组成的程序,所以包大小难以控制。另外就是每个千牛的用户平均拥有20多款的插件,插件安装包非常多,如果包的大小没有得到很好的控制,对于用户的流量和空间都将会造成巨大的消耗。而Bundle包的大小在一定程度上也会影响插件的性能。Bundle包主要包括这样的几部分,rax、组件以及SDK,所以我们可以看到对于每个包而言,公共的部分是非常多的。虽然rax是按需打包的,但是随着业务越来越复杂,一个APP几乎能够覆盖组件库中的全部组件,所以这部分是可以作为公用部分抽取出来的。

所以我们的解决方案就是将公用部分抽取出来放入Main.js里面,Main.js是Weex的运行环境,我们将其内置到Weex的运行环境中去。将公用部分抽取出来之后,Bundle包里面就只剩下了isv的业务代码了,这样使得包的大小能够很好地控制。当然这样的做法所带来的比较大的挑战就是内置包的版本管理和更新升级问题。因为Weex容器的初始化时机是在程序APP加载的时候,这样的方案是没有办法在程序运行的期间做任何处理的。

我们目前正在努力的方向和希望解决的问题就是内置包的管理以及动态升级的问题,这个问题的解决需要Weex框架进行支持。Weex最近提出了Server的概念,允许在插件打开之前构建如图这样的一个环境,将内置包运行在这个环境里面,如果配置环境中配置信息与客户端的版本号一致的话,就去默认地构建环境,如果不一致就会动态地对于出现问题的包进行更新,这样就可以解决内置包的管理以及更新问题。

千牛还提供了更加丰富的能力。在通讯机制方面,这里的通讯机制主要是针对页面级别以及整个插件的生命周期的机制。首先划分的Page级别,也就是单个Bundle内部的事件通讯;其次是插件APP级别的事件通知,也就是插件APP下所有的Bundle之间进行的通讯;第三个就是千牛应用级别的事件通知,会把千牛主体应用发出的全局事件,比如前后端的切换,网络变更等的事件通知给开发者。另外我们还提出了黏性事件的概念,就是当事件没有被消费的时候不会丢失,避免在某些场景出现了事件发出了,但因为还没有注册导致接收不到的情况。

AppIndex主要是解决能力宣称和能力路由的问题,整个插件能提供哪些能力,怎样进行路由都由AppIndex进行管理的。首先对于一个插件而言,它可以将自己对应的能力录入到能力路由表中,并且注册到AppIndex客户端体系中,当进行能力路由的时候会通过权限管理以及能力路由找到实现这个能力的插件,并根据路由表找到具体的页面。其实在QAP1.0就有了这样的一套机制,但是当时只能够返回程序主入口的地址,而在QAP2.0就能精准地定位到每一个页面。

为了精确地寻址,在千牛的客户端中提供了通用的QAP的URI,所有的QAP页面都是通过下图中的这一套URI机制进行寻址的,通过这样的URI就能够定位到每一个页面。

最后为了降低isv的迁移成本我们也做了很多事情。我们实现了Weex+Web的混搭,也就是在前期推广的时候允许isv改造自己的部分页面,也就是将自己的插件的入口页面以及对性能有高要求的页面进行Weex更改,其他要求不高的页面还可以使用Web,这样就能够降低isv的开发成本;除此之外还为isv提供了业务开发实例和开发文档以及一站式的开发工具。

对于开发工具而言,我们提供了QAP的CLI,能够实现创建工程并且导入示例工程、进行调试、打包上传、安装真机测试以及获取最新千牛测试包等功能。但是在将CLI提供给isv的时候也发现了一些问题,比如往往会遇到的平台环境的问题以及依赖安装缓慢的问题。

考虑到以上的问题,我们目前正在做的事情就是将整套相关依赖做成IDE,这样开发者就可以在IDE里面进行一站式工作,可以很方便地找到入口、创建工程并且进行工程调试以及一键安装和上传。