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