Weex如何支撑200w+同时在线的优酷猫晚直播?
阿里妹导读:天猫双十一已经成为被大众普遍接受的文化符号,而猫晚则是连接线下线上的重要节点。2017年天猫晚会的前台直播任务被交给了优酷来承担。 优酷直播,优酷主客团队,优酷架构组等多方组成了联合项目组,合力承担优酷双十一猫晚直播的开发任务。
缘起
虽然优酷直播在线上已经有业务稳定运行,但是我们还是遇到了大量问题需要解决。
除开直播晚会现场这个最重要的功能之外,晚会项目组还规划了点赞/分享有礼,竞猜,开宝箱,红包雨等五花八门的互动玩法,需要在原有的Native直播间上增加大量的功能。
更加雪上加霜的是,晚会的招商并未结束,对直播会场的需求一直在变化。特别是直播会场换肤的需求可能导致会场的框架结构发生大幅度变化,用老的Native直播间应对这种需求变化比较困难。
所以我们决定用Weex重写一个新的优酷直播间,全面还原当前的Native直播间的业务,同时添加对各种双十一互动玩法的支撑。老的Naitve直播间仅仅作为降级的备用直播间。
组件封装
在开始正式工作之前,我们的第一件事情是划分功能模块,确定哪些模块用Weex sdk或者aliweex自带的原生组件实现, 哪些模块需要把现有的Native代码封装为一个Weex Component供Weex业务代码引用。
上图即为双十一优酷直播间的最终形态,其大致的技术架构图和功能如下图所示。
经过评估,我们做出如下模块划分:
会场框架: 由Weex业务代码搭建
回看列表tab: 是一个包含图文的视频列表,由Weex原生实现
聊天tab: 包含了大量聊天气泡动效和复杂的业务逻辑,将原有的聊天室Native代码封装为Weex Component
图文直播tab:包含了投放图片,文字,视频,商品链接等复杂的逻辑,将原有的Native代码封装为Weex Component
播放器组件:将原有的优酷直播播放器Native代码封装为Weex Component
点赞标签: 这个组件被点击或者收到服务端推送的互动消息时会飘出大量的动画,我们的选择是将原有的Native代码封装为Weex component
自定义Tab: 这个组件我们自行封装了一个webview的Component,包含多种功能
1) 利用百川能力加载淘宝商品,实现边看边买 2) 加载互动h5页面,实现红包雨,竞猜等功能 3) 加载阿里星球投放的H5页面等
其余的跳转,分享,监控埋点等功能模块封装为Weex Module供Weex业务代码使用
在功能模块拆分完毕之后,整个直播间已经完全成为组件化,模块化的,可以随意地组合,分解,定制。
无论未来的会场设计如何变化,只要编写新的会场皮肤,根据需要嵌入各种自定义标签,就能组合出需要的直播会场。
互动玩法支撑
运营同学在优酷直播中台的投放系统编辑主持人话题,换肤,红包雨等互动消息后,具体的投放信息会被服务端填入互动玩法动态模板,通过PowerMsg通道下发到端上; 当端上收到此类互动消息之后,直接通过globalEvent发给Weex直播会场,会场解析收到的字段后,根据指令显示主持人话题,拉起宝箱,红包雨页面等。
降级
与一般情况下的Weex页面降级到H5页面不同,我们的降级逻辑是发生加载/跳转/运行异常时,从Weex直播间跳转到Native直播间; 所以我们没有沿用Weex常见的降级逻辑,而是另外实现了一套downgrade逻辑。
遇到的困难及其解决办法
手势冲突
在开发直播会场的过程中,我们遇到了tabbar框架和自定义Weex Component手势冲突的问题。
我们希望上下滑动的手势被当前tab接收,可以在当前列表中上下滑动
我们希望左右滑动的手势被tabbar接收,可以在不同的tab之间切换
但是结合使用tabbar和自定义Weex Component,要么上下左右手势全部被当前tab吃掉,导致无法在tab之间切换。要么上下左右手势都被tabbar吃掉,导致当前tab无法上下滑动
上图是Android View点击事件分发的简化逻辑
父View与子View同时可以滑动时就会产生滑动冲突, 常见套路的一种是在父View的onInterceptTouchEvent()做拦截:
public boolean onInterceptTouchEvent(MotionEvent event){
boolean intercepted = false;
switch(event.getActionMasked){
case MotionEvent.ACTION_DOWN:
intercepted = false;
break;
case MotionEvent.ACTION_MOVE:
if(父控件拦截){
intercepted = true;
}else{
intercepted =false;
}
break;
...
}
...
return intercepted;
}
最后我们的解法是重写了一个自定义Div标签, 将自定义Weex Component嵌入自定义Div标签中,自定义Div标签吃掉上下滑动手势并传给自定义Weex Component,将左右滑动手势抛出让身为父View的tabbar处理,这样就解决了这个手势冲突问题。
然而,直播会场的Weex代码使用了ExpressionBinding来优化滑动性能,新的解法导致ExpressionBinding失效了。
为了解决这个问题,我们又重写了Weex的WXGesture手势识别代码,覆盖掉WXComponent自带的默认手势识别代码,使得ExpressionBinding重新生效。
ExpressionBinding的执行顺序如下:
touchstart -> panstart -> ExpressionBinding panstart ->
ExpressionBinding panmove -> ExpressionBinding panend ->
touchend -> panend
其核心概念是检测出panstart事件,然后执行js层预先传下来的“手势处理逻辑”,而不是将识别出的手势传给js层处理。
我们对自定义Div标签和自定义Weex Component的修改使得ExpressionBinding识别不到panstart事件了。所以我们重写的WXGesture会在合适地方给自己所在的WXComponent发出:
WXGestureType.HighLevelGesture.HORIZONTALPAN
或者:
WXGestureType.HighLevelGesture.VERTICALPAN
事件,人为地触发ExpressionBinding的识别代码执行,最终使得ExpressionBinding可以与自定义Div标签和自定义的Weex Component协同工作。
转屏体验优化
之前优酷直播页面的转屏是直接将Activity转过来,然后让视频撑满屏幕; 若要恢复竖屏则把Activity再转回来,恢复vieoView为原始大小,让其余的布局显示出来。
由于新的Weex直播会场复杂度大大提高,切换横竖屏的体验变得很糟糕,每次切换之后画面要黑屏一会儿才能把布局重新显示出来。
经过多番尝试,我们采用如下的解法来提高体验:竖屏转横屏时,先记录下videoView的各种布局参数,然后将videoView从它的父View中取出,直接attach到当前Window的decorView上。横屏转回竖屏时,将videoView从decorView中取出,add到旧的父View中,然后重设各种布局参数。
经过这个优化之后,转屏体验被大大提升了; 即使在几年前的低端机器上,也能很快速地完成横竖屏切换动作。
视频圆角
如图所示,双十一直播会场的直播视频是嵌入到一个天猫电视机荧幕内的。实现方式是在自定义video标签之上覆盖一个天猫电视机图片,使得视频只从带圆角的框中露出。
这个实现方式在iOS端是没问题的,在Android上却失效了; 视频和图片的层级存在问题,在Android上视频的四个边角仍然会透出来,视觉上非常难看。
我们的解决办法是给自定义播放器组件添加"borderRadius"属性,将UED设计稿中的电视机图片圆角值量出来,设置给自定义video标签,把这个值透传到Native层,经过750px转换之后,将视频VideoView在Native端直接切出合适的圆角。
最终,呈现出来的带圆角视频画面与电视机图片的圆角完美契合,看上去就像是一体的。
页面渲染速度和体验优化
懒加载
Weex直播间是默认是竖屏的,但是也可以转屏幕进入横屏状态。最开始进入Weex直播间时,旧逻辑是同时初始化竖屏下的布局和横屏下的布局,耗时比较长。我们的修改是进入直播间时只初始化竖屏下需要的组件,将横屏下需要的组件延迟加载,真正需要时才创建和初始化。
优化冗余布局
优化减少Layout层级,将设置Visibility为gone的冗余View全部删除。
此外,Weex直播会场页也做了大量的层级/View精简的动作,两者结合起来最终使得加载体验有了很大的提高。
飘赞动画优化
直播间的点赞图标是一个Native封装的Weex Component,当用户手动点击或者收到其他用户的点赞推送时,点在图标会飘出若干个红心或者服务端下发的其他图片。
粗略一看点赞功能实现的没有什么问题,但是在晚会预演的高并发条件下问题就暴露出来了,由于用户量太大,点赞推送消息太多,Android端的点赞动画会变得非常卡顿。
我们的解决办法是做了一个Orange开关,在较低性能的机器上减少或者屏蔽飘赞动画;收到点赞消息推送后,不再立即飘出点赞动画,而是点赞数大于某个阈值,或者大于某个时间间隔才飘出动画,减少端上的渲染压力。
此外,我们注意到飘赞动画是飘出显示区域之后直接销毁,需要飘出新动画时再创建新的图片,我们有考虑引入对象池的技术预先分配一些动画帧并复用,但是由于时间关系未能发布到线上。
减轻服务端压力
1 zcache将Weex bundle JS,图片等静态资源通过zcache推送到客户端上。
(1) 减轻了猫晚当天,客户端请求服务端拉取资源的压力
(2)由于待请求的资源就在本地,大大提高了页面渲染的速度
(3) 提高了页面加载成功率
2 请求合并由于某些mtop接口功能庞杂,Weex和Native代码都要请求,且调用时序无法确定。我们封装了一个Mtop Weex module,兼顾mtop请求和DataPool的功能,Weex和Native代码都通过这个module来发出mtop请求;当某个请求发出之后,短期内对同一个接口的重复请求会被缓存; 第一个请求数据返回之后,结果会通知给所有被缓存的mtop请求方。通过这个小小的优化,我们将服务端QPS压力降低了十多万。
3 猫晚当天,只请求最低限度的服务端接口,不再请求诸如“直播间预告订阅”之类的非必要接口。
双十一猫晚直播成果
最终,优酷的双11直播取得较好的成绩:
1.助力天猫双11,引导点击用户655万。
2.猫晚直播同时在线达209万。
我们在直播会场的关键路径和优酷直播播放器均加上了埋点信息, 根据统计信息:
余温
以双十一直播会场为基础,依据老的标准直播间样式重写了一份皮肤之后,Weex直播间已经在优酷直播业务中全量上线,老的Native直播间已经下线。我们为双十一Weex直播间开发的各种互动玩法已经落地为优酷直播的常态化运营手段。
此次双十一猫晚直播是优酷历史上采用Weex承接的规模最大的项目,也是阿里历史上直播在线人数最高的项目。在各部门的通力合作之下,整个晚会的直播任务运行平稳,没有出现任何意外情况。
在当前的双十一直播会场成果基础上,Weex直播间不仅承担了目前线上全部的优酷直播业务,还会承担即将到来的跨年晚会,春节联欢晚会的直播任务,直播团队还将推出更多酷炫的互动玩法,更加流畅的直播加载体验,敬请期待。
你可能还喜欢
关注「阿里技术」
把握前沿技术脉搏