阿里妹導(dǎo)讀:天貓雙十一已經(jīng)成為被大眾普遍接受的文化符號,而貓晚則是連接線下線上的重要節(jié)點。2017年天貓晚會的前臺直播任務(wù)被交給了優(yōu)酷來承擔(dān)。 優(yōu)酷直播,優(yōu)酷主客團隊,優(yōu)酷架構(gòu)組等多方組成了聯(lián)合項目組,合力承擔(dān)優(yōu)酷雙十一貓晚直播的開發(fā)任務(wù)。?
雖然優(yōu)酷直播在線上已經(jīng)有業(yè)務(wù)穩(wěn)定運行,但是我們還是遇到了大量問題需要解決。
除開直播晚會現(xiàn)場這個最重要的功能之外,晚會項目組還規(guī)劃了點贊/分享有禮,競猜,開寶箱,紅包雨等五花八門的互動玩法,需要在原有的Native直播間上增加大量的功能。
更加雪上加霜的是,晚會的招商并未結(jié)束,對直播會場的需求一直在變化。特別是直播會場換膚的需求可能導(dǎo)致會場的框架結(jié)構(gòu)發(fā)生大幅度變化,用老的Native直播間應(yīng)對這種需求變化比較困難。
所以我們決定用Weex重寫一個新的優(yōu)酷直播間,全面還原當(dāng)前的Native直播間的業(yè)務(wù),同時添加對各種雙十一互動玩法的支撐。老的Naitve直播間僅僅作為降級的備用直播間。
在開始正式工作之前,我們的第一件事情是劃分功能模塊,確定哪些模塊用Weex sdk或者aliweex自帶的原生組件實現(xiàn), 哪些模塊需要把現(xiàn)有的Native代碼封裝為一個Weex Component供Weex業(yè)務(wù)代碼引用。
上圖即為雙十一優(yōu)酷直播間的最終形態(tài),其大致的技術(shù)架構(gòu)圖和功能如下圖所示。
經(jīng)過評估,我們做出如下模塊劃分:
會場框架: 由Weex業(yè)務(wù)代碼搭建
回看列表tab: 是一個包含圖文的視頻列表,由Weex原生實現(xiàn)
聊天tab: 包含了大量聊天氣泡動效和復(fù)雜的業(yè)務(wù)邏輯,將原有的聊天室Native代碼封裝為Weex Component
圖文直播tab:包含了投放圖片,文字,視頻,商品鏈接等復(fù)雜的邏輯,將原有的Native代碼封裝為Weex Component
播放器組件:將原有的優(yōu)酷直播播放器Native代碼封裝為Weex Component
點贊標(biāo)簽: 這個組件被點擊或者收到服務(wù)端推送的互動消息時會飄出大量的動畫,我們的選擇是將原有的Native代碼封裝為Weex component
自定義Tab: 這個組件我們自行封裝了一個webview的Component,包含多種功能
1) 利用百川能力加載淘寶商品,實現(xiàn)邊看邊買 2) 加載互動h5頁面,實現(xiàn)紅包雨,競猜等功能 3) 加載阿里星球投放的H5頁面等
其余的跳轉(zhuǎn),分享,監(jiān)控埋點等功能模塊封裝為Weex Module供Weex業(yè)務(wù)代碼使用
在功能模塊拆分完畢之后,整個直播間已經(jīng)完全成為組件化,模塊化的,可以隨意地組合,分解,定制。
無論未來的會場設(shè)計如何變化,只要編寫新的會場皮膚,根據(jù)需要嵌入各種自定義標(biāo)簽,就能組合出需要的直播會場。
運營同學(xué)在優(yōu)酷直播中臺的投放系統(tǒng)編輯主持人話題,換膚,紅包雨等互動消息后,具體的投放信息會被服務(wù)端填入互動玩法動態(tài)模板,通過PowerMsg通道下發(fā)到端上; 當(dāng)端上收到此類互動消息之后,直接通過globalEvent發(fā)給Weex直播會場,會場解析收到的字段后,根據(jù)指令顯示主持人話題,拉起寶箱,紅包雨頁面等。
與一般情況下的Weex頁面降級到H5頁面不同,我們的降級邏輯是發(fā)生加載/跳轉(zhuǎn)/運行異常時,從Weex直播間跳轉(zhuǎn)到Native直播間; 所以我們沒有沿用Weex常見的降級邏輯,而是另外實現(xiàn)了一套downgrade邏輯。
在開發(fā)直播會場的過程中,我們遇到了tabbar框架和自定義Weex Component手勢沖突的問題。
我們希望上下滑動的手勢被當(dāng)前tab接收,可以在當(dāng)前列表中上下滑動
我們希望左右滑動的手勢被tabbar接收,可以在不同的tab之間切換
但是結(jié)合使用tabbar和自定義Weex Component,要么上下左右手勢全部被當(dāng)前tab吃掉,導(dǎo)致無法在tab之間切換。要么上下左右手勢都被tabbar吃掉,導(dǎo)致當(dāng)前tab無法上下滑動
上圖是Android View點擊事件分發(fā)的簡化邏輯
父View與子View同時可以滑動時就會產(chǎn)生滑動沖突, 常見套路的一種是在父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標(biāo)簽, 將自定義Weex Component嵌入自定義Div標(biāo)簽中,自定義Div標(biāo)簽吃掉上下滑動手勢并傳給自定義Weex Component,將左右滑動手勢拋出讓身為父View的tabbar處理,這樣就解決了這個手勢沖突問題。
然而,直播會場的Weex代碼使用了ExpressionBinding來優(yōu)化滑動性能,新的解法導(dǎo)致ExpressionBinding失效了。
為了解決這個問題,我們又重寫了Weex的WXGesture手勢識別代碼,覆蓋掉WXComponent自帶的默認(rèn)手勢識別代碼,使得ExpressionBinding重新生效。
ExpressionBinding的執(zhí)行順序如下:
touchstart?->?panstart?->?ExpressionBinding panstart?->
ExpressionBinding panmove?->?ExpressionBinding panend?->?
touchend?->?panend
其核心概念是檢測出panstart事件,然后執(zhí)行js層預(yù)先傳下來的“手勢處理邏輯”,而不是將識別出的手勢傳給js層處理。
我們對自定義Div標(biāo)簽和自定義Weex Component的修改使得ExpressionBinding識別不到panstart事件了。所以我們重寫的WXGesture會在合適地方給自己所在的WXComponent發(fā)出:
WXGestureType.HighLevelGesture.HORIZONTALPAN
或者:
WXGestureType.HighLevelGesture.VERTICALPAN
事件,人為地觸發(fā)ExpressionBinding的識別代碼執(zhí)行,最終使得ExpressionBinding可以與自定義Div標(biāo)簽和自定義的Weex Component協(xié)同工作。
之前優(yōu)酷直播頁面的轉(zhuǎn)屏是直接將Activity轉(zhuǎn)過來,然后讓視頻撐滿屏幕; 若要恢復(fù)豎屏則把Activity再轉(zhuǎn)回來,恢復(fù)vieoView為原始大小,讓其余的布局顯示出來。
由于新的Weex直播會場復(fù)雜度大大提高,切換橫豎屏的體驗變得很糟糕,每次切換之后畫面要黑屏一會兒才能把布局重新顯示出來。
經(jīng)過多番嘗試,我們采用如下的解法來提高體驗:豎屏轉(zhuǎn)橫屏?xí)r,先記錄下videoView的各種布局參數(shù),然后將videoView從它的父View中取出,直接attach到當(dāng)前Window的decorView上。橫屏轉(zhuǎn)回豎屏?xí)r,將videoView從decorView中取出,add到舊的父View中,然后重設(shè)各種布局參數(shù)。
經(jīng)過這個優(yōu)化之后,轉(zhuǎn)屏體驗被大大提升了; 即使在幾年前的低端機器上,也能很快速地完成橫豎屏切換動作。
如圖所示,雙十一直播會場的直播視頻是嵌入到一個天貓電視機熒幕內(nèi)的。實現(xiàn)方式是在自定義video標(biāo)簽之上覆蓋一個天貓電視機圖片,使得視頻只從帶圓角的框中露出。?
這個實現(xiàn)方式在iOS端是沒問題的,在Android上卻失效了; 視頻和圖片的層級存在問題,在Android上視頻的四個邊角仍然會透出來,視覺上非常難看。
我們的解決辦法是給自定義播放器組件添加"borderRadius"屬性,將UED設(shè)計稿中的電視機圖片圓角值量出來,設(shè)置給自定義video標(biāo)簽,把這個值透傳到Native層,經(jīng)過750px轉(zhuǎn)換之后,將視頻VideoView在Native端直接切出合適的圓角。
最終,呈現(xiàn)出來的帶圓角視頻畫面與電視機圖片的圓角完美契合,看上去就像是一體的。
懶加載
Weex直播間是默認(rèn)是豎屏的,但是也可以轉(zhuǎn)屏幕進入橫屏狀態(tài)。最開始進入Weex直播間時,舊邏輯是同時初始化豎屏下的布局和橫屏下的布局,耗時比較長。我們的修改是進入直播間時只初始化豎屏下需要的組件,將橫屏下需要的組件延遲加載,真正需要時才創(chuàng)建和初始化。
優(yōu)化冗余布局
優(yōu)化減少Layout層級,將設(shè)置Visibility為gone的冗余View全部刪除。
此外,Weex直播會場頁也做了大量的層級/View精簡的動作,兩者結(jié)合起來最終使得加載體驗有了很大的提高。
飄贊動畫優(yōu)化
直播間的點贊圖標(biāo)是一個Native封裝的Weex Component,當(dāng)用戶手動點擊或者收到其他用戶的點贊推送時,點在圖標(biāo)會飄出若干個紅心或者服務(wù)端下發(fā)的其他圖片。
粗略一看點贊功能實現(xiàn)的沒有什么問題,但是在晚會預(yù)演的高并發(fā)條件下問題就暴露出來了,由于用戶量太大,點贊推送消息太多,Android端的點贊動畫會變得非??D。
我們的解決辦法是做了一個Orange開關(guān),在較低性能的機器上減少或者屏蔽飄贊動畫;收到點贊消息推送后,不再立即飄出點贊動畫,而是點贊數(shù)大于某個閾值,或者大于某個時間間隔才飄出動畫,減少端上的渲染壓力。
此外,我們注意到飄贊動畫是飄出顯示區(qū)域之后直接銷毀,需要飄出新動畫時再創(chuàng)建新的圖片,我們有考慮引入對象池的技術(shù)預(yù)先分配一些動畫幀并復(fù)用,但是由于時間關(guān)系未能發(fā)布到線上。
1?zcache將Weex bundle JS,圖片等靜態(tài)資源通過zcache推送到客戶端上。
(1) 減輕了貓晚當(dāng)天,客戶端請求服務(wù)端拉取資源的壓力
(2)由于待請求的資源就在本地,大大提高了頁面渲染的速度
(3) 提高了頁面加載成功率
2?請求合并由于某些mtop接口功能龐雜,Weex和Native代碼都要請求,且調(diào)用時序無法確定。我們封裝了一個Mtop Weex module,兼顧mtop請求和DataPool的功能,Weex和Native代碼都通過這個module來發(fā)出mtop請求;當(dāng)某個請求發(fā)出之后,短期內(nèi)對同一個接口的重復(fù)請求會被緩存; 第一個請求數(shù)據(jù)返回之后,結(jié)果會通知給所有被緩存的mtop請求方。通過這個小小的優(yōu)化,我們將服務(wù)端QPS壓力降低了十多萬。
3?貓晚當(dāng)天,只請求最低限度的服務(wù)端接口,不再請求諸如“直播間預(yù)告訂閱”之類的非必要接口。
最終,優(yōu)酷的雙11直播取得較好的成績:
1.助力天貓雙11,引導(dǎo)點擊用戶655萬。
2.貓晚直播同時在線達209萬。
我們在直播會場的關(guān)鍵路徑和優(yōu)酷直播播放器均加上了埋點信息, 根據(jù)統(tǒng)計信息:
以雙十一直播會場為基礎(chǔ),依據(jù)老的標(biāo)準(zhǔn)直播間樣式重寫了一份皮膚之后,Weex直播間已經(jīng)在優(yōu)酷直播業(yè)務(wù)中全量上線,老的Native直播間已經(jīng)下線。我們?yōu)殡p十一Weex直播間開發(fā)的各種互動玩法已經(jīng)落地為優(yōu)酷直播的常態(tài)化運營手段。
此次雙十一貓晚直播是優(yōu)酷歷史上采用Weex承接的規(guī)模最大的項目,也是阿里歷史上直播在線人數(shù)最高的項目。在各部門的通力合作之下,整個晚會的直播任務(wù)運行平穩(wěn),沒有出現(xiàn)任何意外情況。
在當(dāng)前的雙十一直播會場成果基礎(chǔ)上,Weex直播間不僅承擔(dān)了目前線上全部的優(yōu)酷直播業(yè)務(wù),還會承擔(dān)即將到來的跨年晚會,春節(jié)聯(lián)歡晚會的直播任務(wù),直播團隊還將推出更多酷炫的互動玩法,更加流暢的直播加載體驗,敬請期待。
你可能還喜歡
關(guān)注「阿里技術(shù)」
把握前沿技術(shù)脈搏
評論
查看更多