Tetris Native揭秘|有道詞典動態(tài)化運營引擎

Tetris Native是有道詞典端側動態(tài)渲染引擎,目前已作為多個業(yè)務的運營投放容器,支持跨端UI動態(tài)化發(fā)布及多種樣式,助力有道詞典流量變現(xiàn)?!禩etris Native揭秘》系列文章將詳細介紹Tetris Native的設計理念和詳細落地方案。

在介紹Tetris Native之前,先給Tetris打個廣告。Tetris是H5低代碼平臺,一直以來都被有道詞典廣泛使用。該平臺已經(jīng)在我們的會員、課程、社區(qū)等業(yè)務投放頁中得到應用,顯著提升了運營和市場投放頁面的開發(fā)迭代效率。轉載請注明來源:「申國駿」

Tetris頁面展示.png

Tetris Native是一套動態(tài)化投放技術方案,旨在提升運營和廣告投放效率。與Tetris不同的是,Tetris Native在客戶端本地進行渲染,它屬于端側的服務驅動UI(Server-Driven UI)技術。服務端下發(fā)的數(shù)據(jù)包括圖片、文本、視頻和卡片等UI組件的樣式布局及內容。通過服務驅動UI的方式,我們能夠在客戶端不需要更新版本的情況下,新增或調整現(xiàn)有頁面的UI組件內容和布局,實現(xiàn)快速的運營開發(fā)迭代。

我們先來一睹為快,下面是有道詞典線上投放的動態(tài)化運營版面展示。

案例一:有道詞典頭部動態(tài)版面運營位.png
案例二:有道詞典底部動態(tài)版面運營位.png
案例三:線上其他動態(tài)化版面展示.jpg

如上述案例所示,Tetris Native已在有道詞典中大量使用。就使用方式而言,針對不同的業(yè)務場景,可以有三種使用方式。

三種使用方式.png
  1. 第一種方式:服務端下發(fā)帶有業(yè)務數(shù)據(jù)的頁面描述DSL,客戶端進行渲染。
    優(yōu)勢:在云端合成業(yè)務數(shù)據(jù)和頁面樣式描述DSL,客戶端渲染DSL JSON。樣式修改或新增只需更改投放后臺,無需客戶端發(fā)版。適合樣式需要頻繁修改的業(yè)務,但要求投放后臺和服務高度配合,后臺需處理業(yè)務數(shù)據(jù)的同時考慮端側布局樣式構建。目前主要用于首頁快速運營迭代的地方。
  2. 第二種方式:服務端下發(fā)純業(yè)務數(shù)據(jù),客戶端構建頁面渲染DSL后進行渲染。
    優(yōu)勢:服務端僅下發(fā)業(yè)務數(shù)據(jù),無需額外改動??蛻舳私Y合業(yè)務數(shù)據(jù)生成頁面描述DSL并進行渲染。與第一種開發(fā)模式相比,投放后臺和服務端無感知,不過依賴客戶端發(fā)版??蛻舳丝赏ㄟ^構建DSL JSON實現(xiàn)雙端樣式一致,重用已有UI邏輯,降低業(yè)務開發(fā)難度。適合日常樣式改動較少的頁面。
  3. 第三種方式:服務端下發(fā)純業(yè)務數(shù)據(jù)和繪制DSL渲染JS腳本,端側執(zhí)行JS腳本生成頁面渲染DSL后進行渲染。
    優(yōu)勢:不需改動現(xiàn)有服務端業(yè)務數(shù)據(jù)邏輯,與第二種方式類似對投放后臺和服務端無感知,但不依賴客戶端發(fā)版。客戶端通過執(zhí)行JS腳本生成DSL JSON來實現(xiàn)動態(tài)修改樣式需求,無需侵入現(xiàn)有服務端和投放系統(tǒng)邏輯。適用于業(yè)務數(shù)據(jù)變化不大的情況下修改樣式,不過這對端側渲染性能有一定影響。目前尚未在線上使用。

以上介紹了動態(tài)渲染引擎Tetris Native的三種使用方式,以及它們的優(yōu)缺點和適用業(yè)務場景。接下來,我們將回顧設計動態(tài)渲染引擎的初衷,解決的業(yè)務困境,需求分析和技術選型過程,以及介紹目前Tetris Native的整體開發(fā)進度。

需求分析

在使用動態(tài)化投放方案之前,我們面臨的主要問題是無法快速進行投放試驗。由于不同的投放樣式需要進行端側開發(fā)和發(fā)布,整個流程較為耗時。尤其是在首頁設計了近20種不同的投放樣式時,按照傳統(tǒng)的開發(fā)流程,需要在安卓和iOS端各開發(fā)20種樣式。而且,如果日后需要對這些樣式進行修改或新增,還需要進行額外的發(fā)布。顯然,傳統(tǒng)的開發(fā)方式需要轉變?yōu)楦屿`活的方式。總結來說,我們面臨的問題主要有兩個方面:一是傳統(tǒng)開發(fā)方式無法支持運營快速進行投放試驗;二是研發(fā)效率和上線流程妨礙了快速迭代的實現(xiàn)。

運營投放具有以下特點:主要以卡片組合為投放樣式,每個卡片承載不同的業(yè)務投放。一個投放版面由多種業(yè)務卡片組合而成,頁面包含多個投放版面。單個業(yè)務素材會在不同樣式的卡片中出現(xiàn)。

素材、卡片、版面、頁面之間的關系.png

針對上述的業(yè)務需求,因為運營投放的樣式多為卡片的組合,我們可以考慮開發(fā)一套以卡片為基礎的動態(tài)運營投放系統(tǒng)。由于我們業(yè)務的落地頁基本支持deeplink的跳轉方式,因此我們僅需要處理卡片的deeplink跳轉以及對應的展示和點擊統(tǒng)計邏輯即可。

對于端側,可以總結有以下的技術需求:

  1. 支持動態(tài)發(fā)布(服務端下發(fā)卡片和素材內容及布局)
  2. 支持多種卡片展示樣式(平鋪、橫豎滾動、橫豎列表等)
  3. 支持多種卡片內容格式(文本、圖片、動圖、視頻等)
  4. 渲染速度快
  5. 服務端下發(fā)數(shù)據(jù)盡量少保證傳輸速度快
  6. 對卡片展示和點擊進行自動上報

對于投放后臺,有以下技術需求:

  1. 支持創(chuàng)建素材并綁定素材跳轉的deeplink落地頁
  2. 支持編輯投放的版面樣式,并綁定對應的素材
  3. 生成素材內容和樣式描述DSL,加入需要統(tǒng)計上報字段
  4. 支持編輯投放的生效規(guī)則和投放策略

在明確了上述的技術需求之后,我們對業(yè)內不同的技術方案進行評估,考慮其可行性、適用性和性能等因素。這樣的分析對比有助于我們選擇最適合我們需求的技術方案,并為后續(xù)的系統(tǒng)設計和開發(fā)提供指導。

技術選型

就實現(xiàn)客戶端無需發(fā)版即可實現(xiàn)UI動態(tài)渲染而言,有多種技術選擇。首先,可以采用像React Native或WEEX這類類似Web開發(fā)的方式。這種方法允許在移動端使用前端框架如Vue進行UI渲染,提供了豐富的UI控件,并具備成熟的社區(qū)支持。然而,與原生控件相比,性能略有損耗,而且存在一些交互差異。

另一種選擇是使用Flutter動態(tài)化,例如58的Fair、騰訊的mxflutter以及阿里的karken。這些方法支持前端開發(fā)方式,并通過底層調用Flutter實現(xiàn)跨平臺動態(tài)渲染。然而,這些方案在成熟度和開發(fā)維護成本方面尚有待改進。

還有一種方法是使用Webview來解決UI動態(tài)修改而無需發(fā)版的問題,但Webview的性能較差,不適合在高頻用戶路徑中直接使用。

最后,可以考慮采用服務驅動UI(Server-Driven UI)的方案,如阿里的Tangram和優(yōu)酷的Gaia-X。這些方法通過DSL描述來指導客戶端構建原生UI,需要對支持的UI控件進行DSL定義,然后在客戶端進行視圖構建、布局和渲染。雖然這些方法目前支持的UI控件較少,但由于使用原生控件,性能較好。

技術選擇 優(yōu)點 缺點
React Native/WEEX - 類似Web開發(fā)方式 <br />- 豐富的UI控件 <br />- 社區(qū)支持 - 性能略有損耗 <br />- 存在交互差異
Flutter動態(tài)化(如Fair、mxflutter、karken) - 支持前端開發(fā)方式 <br />- 跨平臺動態(tài)渲染 - 成熟度和開發(fā)維護成本待改進
Webview - 無需發(fā)版實現(xiàn)UI修改 <br />- 適用于低頻使用路徑 - 性能較差 <br />- 不適合在高頻用戶路徑使用
服務驅動UI(Tangram、Gaia-X) - 使用原生控件<br />- 性能較好 - 支持的UI控件較少

考慮到我們項目的需求,主要以卡片組合形式為主,并且對于UI交互要求不太復雜。同時,我們對于性能和開發(fā)效率有著較高的要求?;谶@些考慮,我們決定采用服務驅動UI的技術方案來推進項目。接下來,我們將對服務端驅動UI技術方案進行詳細的業(yè)內方案對比。

在服務端驅動用戶界面(Server Driver UI)的技術方案中,我們需要仔細考慮兩個關鍵方面,即渲染引擎和領域特定語言(DSL)的選擇。這兩個方面的決策將直接影響我們后續(xù)的開發(fā)方案。因此,我們需要對這些方面進行深入的分析和評估,以確保最終選擇的方案能夠滿足我們的需求并具備高度的可擴展性和靈活性。渲染引擎的選擇涉及到考慮性能、跨平臺支持、可定制性以及對現(xiàn)有技術棧的集成能力等因素。而在選擇DSL語言時,我們需要評估其表達能力、易用性、可維護性以及對業(yè)務邏輯的良好支持等特性。通過深入研究和比較,我們將能夠制定出一個既具備技術優(yōu)勢又能夠滿足業(yè)務需求的綜合解決方案。

基于Flex布局框架

開源的跨平臺Flex布局引擎,例如facebook/yoga以及Tencent/Taitank,提供了底層的跨平臺渲染布局引擎。利用這些引擎可以實現(xiàn)跨平臺的動態(tài)渲染框架。使用這種技術棧比較有代表性的動態(tài)化框架有美團的MTFlexbox以及知乎的Morph。這些框架的整體架構邏輯如下所示。

基于flex跨端框架.png

在這個框架下,由于底層依賴于Flex的跨端渲染引擎,因此所有UI布局的描述都必須采用Flex布局方式。Flex跨端布局引擎具有成熟可靠的優(yōu)勢,且Flex布局描述通用易懂。然而,與常規(guī)約束布局相比,將樣式轉化為Flex布局描述需要額外工作,并且不可避免地增加了View的層級嵌套,增加了整體DSL描述的復雜度和數(shù)據(jù)傳輸量。同時,facebook/yoga以及Tencent/Taitank有別于我們原生開發(fā)的View體系,在布局問題的維護和調試方面較為困難。

基于聲明式UI框架

隨著Jetpack Compose和SwiftUI等聲明式UI框架的廣泛應用和不斷發(fā)展,將DSL轉換為聲明式UI框架成為一種可行的選擇。特別是Compose Multiplatform的出現(xiàn),理論上可以將DSL轉換為適用于多平臺的聲明式UI。然而,目前引入Jetpack Compose和SwiftUI并沒有明顯的收益,聲明式UI的引入會增加應用程序的包體積并影響啟動速度。因此,我們目前沒有采用這一方案。盡管一些技術論壇上存在相關的嘗試和分享,例如:《Jetpack Compose Enables JSON Defined View Layout》,但目前業(yè)內還沒有一個完整的基于聲明式UI的動態(tài)化框架。聲明式UI框架是未來的發(fā)展趨勢,我們將繼續(xù)關注,并在認為基于聲明式UI的動態(tài)化方案具有額外優(yōu)勢,如性能和維護性等方面時考慮進行切換。

基于原生UI框架

基于原生UI框架是指我們將DSL轉換綁定到安卓和iOS的原生View中,并通過原生布局的方式或者引入對應平臺的Flex布局對View進行渲染。采用這種方式雖然要求各端編寫相應的代碼來創(chuàng)建和渲染DSL對應的View,不過這種方式有以下幾個好處:

  1. 更接近熟悉的原生開發(fā),無需額外學習成本
  2. 性能與原生一樣快
  3. 在View的擴展和維護方面相對容易
  4. 可與現(xiàn)有的原生控件頁面很好集成,具有良好的互操作性。

基于上述考慮,我們選擇了基于原生的View框架作為底層布局和渲染的基礎。業(yè)內有兩個具有影響力的基于原生UI框架的動態(tài)化項目,分別是天貓的Tangram(alibaba/Tangram-Androidalibaba/Tangram-iOS)以及優(yōu)酷的alibaba/GaiaX。我們分別對這兩個項目進行詳細的分析。

Tangram

Tangram是阿里生態(tài)中淘寶&天貓開源的動態(tài)化渲染方案。該項目的主要代碼貢獻發(fā)生在2017年至2019年期間,目前已停止維護。Tangram實現(xiàn)了基于列表的多樣式卡片式布局,支持一拖N、懸浮和吸頂效果,以及輪播等卡片樣式的動態(tài)化布局。它包含了JSON樣式解析器、數(shù)據(jù)解析綁定器、VirtualView渲染框架、VirtualLayout(LazyScroolView for iOS)布局框架、預設組件卡片庫,以及布局預覽、曝光點擊處理等輔助工具。整體流程可參考下圖:

Tangram工作流程.png

Tangram的實現(xiàn)思路給我們提供了有價值的啟示和幫助,但它整體效果并不完全滿足我們自身的業(yè)務需求。此外Tangram已處于停止維護狀態(tài),其代碼邏輯龐大且復雜。因此,在Tetris Native中,我們只是借鑒了Tangram一些View生成的流程和思路,并沒有基于它進行開發(fā)。

GaiaX

GaiaX是阿里生態(tài)中優(yōu)酷開源的跨端動態(tài)化模板引擎,配套有卡片編輯器,文檔較全且在活躍迭代。目前,網(wǎng)易云音樂也采用該框架來實現(xiàn)首頁的動態(tài)化。整體思路與我們的目標相似,即通過將DSL轉換為相應的原生業(yè)務卡片UI控件。其實現(xiàn)的整體思路和方案與Tetris Native類似,也是將DSL轉換為虛擬節(jié)點樹,再轉換為原生View樹。其中DSL包含描述UI控件層級關系的Layout JSON、描述樣式的CSS和描述數(shù)據(jù)的Data JSON三部分。GaiaX整體框架實現(xiàn)流程如下:

GaiaX工作流程.png

在啟動Tetris Native項目時,GaiaX還沒有進入公眾視野,因此我們沒有基于GaiaX來開發(fā)動態(tài)化模板引擎。相比Tetris Native,GaiaX雖然有配套的卡片編輯器,但是無法和我們自己的投放系統(tǒng)進行結合(參考云音樂自研的投放系統(tǒng))。此外,GaiaX缺乏我們業(yè)務需要的一些特性(如視頻、不規(guī)則圓角、Flex布局等),同時GaiaX樣式與數(shù)據(jù)分離增加了數(shù)據(jù)構造的復雜度和數(shù)據(jù)傳輸量,沒有帶來實質優(yōu)勢。因此我們將參考GaiaX的實現(xiàn)方式,吸取其中比較好的部分(如事件和JS引擎的引入),以完善和迭代Tetris Native。

Tetris Native

總體而言,跨端服務驅動UI框架的技術選型涉及以下三個方面的方案選擇。首先,需要選擇DSL層的格式,即XML、JSON還是YAML,并決定是否需要進行樣式數(shù)據(jù)分離。其次,需要選擇Layout層的布局引擎,是跨端的Flex布局引擎、聲明式UI框架,還是原生的布局方式。最后,在View層需要選擇使用原生View還是聲明式UI控件。根據(jù)我們團隊的技術條件、現(xiàn)有項目架構和業(yè)務需求,在Tetris Native中我們做出以下技術選型:

  • 首先,明確我們的目標是根據(jù)業(yè)務需求來抽離共性,而不是構建類似RN或其他類Web開發(fā)引擎,不自嗨

  • DSL層,使用JSON作為數(shù)據(jù)傳輸格式,簡潔明了,減少數(shù)據(jù)傳輸量

  • View層,基于基礎原生組件構建,考慮與現(xiàn)有項目的互操作性和可維護性,暫時不引入聲明式UI組件

  • Layout層,使用原生相對布局和流式布局,避免引入難以維護的三方渲染引擎

技術架構和流程概覽如下圖所示:

Tetris Native技術架構圖.png
Tetris Native工作流程.png

詳細設計方案和落地問題處理將在下一篇文章中進行詳細介紹,敬請期待。

DSL設計

對于動態(tài)模板引擎而言,DSL的設計是尤為關鍵的。我們遵循以下三個原則來設計DSL:

  1. 直觀:字段定義應該能夠直觀地傳達其含義。
  2. 簡潔:在保持直觀性的前提下,盡量保持簡潔。
  3. 通用:盡量使用已有的安卓和iOS原生參數(shù),避免引入新的概念。

以下是Tetris Native支持的能力DSL一覽。

根布局配置
設計稿寬度 (designWidth) 固定大小 (fixScale)<br />- 默認根據(jù)designWidth和當前view的寬度進行元素縮放 false <br />- 使用原生縮放策略 true
邊距 (marginLeft, marginRight, marginTop, marginBottom) 背景(bg,bgDark)
基礎屬性
位置&寬高(l, t, r, b, w, h) 邊框(borderWidth, borderColor, borderColorDark)
圓角(borderRadiusArray, borderRadius) 陰影(shadowXOffset, shadowYOffset, shadowBlur, shadowSpread, shadowColor, shadowColorDark)
圖片
拉伸方式(scaleType)<br />- 兩邊拉伸,默認 (fillXY) <br />- 按比例展示全部,圖片小于view部分透明(centerInside) <br />- 按比例填充圖片,多余部分被裁剪(centerCrop) 背景圖片或者色值(src, srcDark)
占位色值(placeholder, placeholderDark) 占位色值(placeholder, placeholderDark)
取色填充背景,是否獲取當前圖片的主題色值填充背景卡片(colorToBg) 取色失敗默認填充值(colorToBgPlaceholder, colorToBgPlaceholderDark)
視頻
拉伸方式(scaleType)<br />- 兩邊拉伸,默認 (fillXY)<br />- 按比例展示全部,視頻小于view部分透明(centerInside)<br />- 按比例填充視頻,多余部分被裁剪(centerCrop) 視頻鏈接 (videoSrc)
封面背景圖片或者色值(coverSrc, coverSrcDark) 封面占位色值(coverPlaceholder, coverPlaceholderDark)
視頻在多幀卡片中的輪播時長 (showInterval 單位為秒)
文本
文本內容(text) 字體色值(color, colorDark)
字體大小(size) 字體樣式(textStyle)<br />- 正常,默認(normal) <br />- 粗體(bold)
文本最大行數(shù)(maxLines) 超過行數(shù)顯示樣式 (ellipsize)<br />- 默認,尾部… (end) <br />- 走馬燈 (marquee)
文本對齊方式(align) 文本內邊距 (contentInset)
文本左側或右側圖片(drawableLeft, drawableLeftDark, drawableRight, drawableRightDark) 文本陰影(textShadowXOffset, textShadowYOffset, textShadowRadius, textShadowColor, textShadowColorDark)
卡片
背景色值(bg, bgDark) 跳轉Deeplink(url)
子節(jié)點(children)
多幀卡片
多幀布局間隔(frameSpace) 幀寬度(frameWidth)
背景色值(bg, bgDark) 多幀指示器(indicator)<br />- 隱藏指示器,默認(none) <br />- 左下方(left) <br />- 中部下方(center) <br />- 右下方(right)
多幀指示器邊距(indicatorMargin) 自動循環(huán)(autoLoop)
自動循環(huán)禁止用戶操作(disableUserScroll) 設置自動循環(huán)間隔(loopIntervalMs)
是否循環(huán)(isLoop,對于frameWidth * 2 + frameWidth >= width的情況,默認會采用循環(huán)方式,若不希望循環(huán),可以設置為FALSE) 通屏(isExtendToEdge,設置之后可以讓卡片展示到外層padding位置,框架會處理與外邊框對齊)
軸向 (axis)<br />- 橫向(默認)horizontal<br />- 豎向 vertical 包含的卡片 (cards)
Flex流式布局卡片
背景色值(bg, bgDark) 行間距 (lineSpacing)
同行元素間距 (interitemSpacing) 元素是否另起一行 (wrapBefore,以flexParam參數(shù)放到每個元素之中)
縱向方向布局方式 (alignContent)<br />- start<br />- end<br />- center<br />- spaceBetween<br />- spaceAround<br />- spaceEvenly 行水平方向布局方式 (justifyContent)<br />- start<br />- end<br />- center<br />- spaceBetween<br />- spaceAround<br />- spaceEvenly
同一行元素在縱向布局方式 (alignItem)<br />- start<br />- end<br />- center<br />- stretch

運營投放邏輯

從運營的角度來看,模板動態(tài)化的端側實現(xiàn)僅僅是整體框架的一部分。以下是我們整體動態(tài)化運營投放、測試和服務上線的介紹。

首先,產品和運營團隊會編寫需要試驗的所有投放樣式的需求文檔。設計師會根據(jù)產品需求文檔設計試驗投放樣式的UI稿。根據(jù)UI稿,我們會生成動態(tài)版面的JSON描述。然后,在投放后臺中,我們需要新增這些試驗版面的投放流程。運營團隊會上傳圖文等素材,并指定素材對應的業(yè)務落地頁,生成不同樣式的卡片。接著,運營團隊會進入需要試驗的版面,進行素材投放的編輯,并確定每個版面所需的素材組合。

在設置好試驗版面的素材內容后,運營團隊會在投放后臺系統(tǒng)中設置這些試驗版面的投放策略。當投放策略設置完成,我們可以預覽投放的頁面,并將其發(fā)布到測試環(huán)境。測試團隊會在測試環(huán)境中對新增樣式進行測試,當測試通過后,我們就可以將其發(fā)布到線上,向用戶展示。

在用戶瀏覽和點擊投放試驗卡片的過程中,我們會根據(jù)頁面描述JSON中的統(tǒng)計字段自動收集和上報日志。最后,運營團隊可以通過我們的日志報表查看不同版面和素材對用戶點擊率的影響,以便決定使用點擊率更高的版面和素材。下圖展示了投放流程和投放系統(tǒng)的測試及上線流程。

運營投放整體流程.png

通過引入Tetris Native動態(tài)化運營,我們成功降低了客戶端開發(fā)和迭代所需的開發(fā)成本和時間投入,從而提高了運營投放的效率。此外,我們還實現(xiàn)了規(guī)范的自動日志上報、廣告獲取和自動展示上報等功能,消除了過去產品和開發(fā)團隊之間繁瑣的日志對接和測試驗收流程,進一步加速了整體運營投放的效率。

總結展望

Tetris Native經(jīng)歷了多個線上版本的迭代,從想法的萌生到正式立項,再發(fā)展到了目前相對穩(wěn)定的階段。在迭代過程中,我們不斷提煉業(yè)務邏輯的共性,并持續(xù)優(yōu)化整體框架的設計和性能。以下是Tetris Native整體開發(fā)和迭代的過程:

Tetris Native 開發(fā)歷程.png

Tetris Native接下來的Roadmap會繼續(xù)結合業(yè)務產品需求,繼續(xù)往以下這些方面進行迭代優(yōu)化

  • 探索DSL編輯優(yōu)化的方法,將DSL以類似于API的方式進行發(fā)布,降低使用門檻
  • 將庫中原生View構建邏輯進行抽離,支持調用方復用和快速構建
  • 探索AI在這里提升效率的潛力和應用

以上介紹了網(wǎng)易有道動態(tài)化運營引擎Tetris Native的初衷以及迭代開發(fā)過程,同時詳細闡述了有道詞典在動態(tài)化運營投放方面的整體邏輯,并展示了引入Tetris Native后的效率提升,希望能為大家的提供一些思路和帶來收益。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容