天天看點

愛奇藝RN低代碼引擎:千變萬化、快速搭建的萬花筒

嘉賓 | 甘泉

編輯 | 李慧文

React Native 是具有高動态化能力的跨平台開發架構,低代碼是近幾年非常熱門的趨勢,而愛奇藝早在 2018 年就嘗試将二者結合,開發出了萬花筒引擎和專題頁低代碼平台,用于快速搭建愛奇藝 App 中的各類内容展示型頁面,賦能不會寫代碼的内容營運和編輯們,針對熱門的綜藝和影視劇内容,用很少的人力投入就能快速搭建出具有豐富排版和動畫效果的專題頁面,并直接投放上線。

在 2021 年 5 月北京 QCon 全球軟體開發大會上,愛奇藝基線研發部進階經理甘泉分享了愛奇藝設計和應用萬花筒引擎和低代碼平台的實踐經驗、遇到的挑戰以及解決思路。我們整理了他的演講,以期解決您在 React Native 低代碼系統架構設計時可能遭遇的某些問題。(下文以甘泉老師第一人稱叙述)

愛奇藝專題頁面包含豐富排版和動畫效果。這類頁面均由以下低代碼方案實作:用零代碼搭建頁面、用低代碼開發頁面内正常元件實作正常動畫、用專業代碼開發頁面内定制化元件實作個性動畫。

1

一、業務背景

移動端正常頁面開發流程包括:提出需求、需求稽核、視覺設計、前後端開發、測試驗證、修複 Bug、跟版上線七步,涉及到産品經理、設計師、工程師、QA 等角色。

愛奇藝RN低代碼引擎:千變萬化、快速搭建的萬花筒

專題頁開發流程與一般頁面在流程、人員、成本上、釋出周期、向前相容性上均存在差異。專題頁開發隻有提出需求、視覺設計、搭建頁面、自測驗證、投放上線五步。其中,需求是由編輯提出的。

在專題頁開發中,開發流程需極度簡化才能友善編輯操作,頁面需花樣豐富才能吸引使用者,搭建要足夠快捷才可保證内容時效性,增加新布局樣式和特性需不依賴 App 發版才可便于更新。

為實作以上需求,我們對比了 H5、RN 和當時愛奇藝已有的自研的原生 DSL 方案的優缺點,綜合成本、性能、動态性等多方面的考慮,決定自研一個結合 RN 和 DSL 的新方案:Kaleidoscope 引擎(萬花筒引擎)。

愛奇藝RN低代碼引擎:千變萬化、快速搭建的萬花筒

2

二、Kaleidoscope DSL 設計思想

這個引擎之是以被命名為 Kaleidoscope(萬花筒),是因為其靈感來自真正的萬花筒。萬花筒是在圓筒一端放入彩色碎片,圓筒中間放置三棱鏡,從另一端的孔中即可觀測到對稱的美麗圖像,結構簡單、體積小巧,卻千變萬化。Kaleidoscope 采取了相通的設計思路。

愛奇藝RN低代碼引擎:千變萬化、快速搭建的萬花筒

Kaleidoscope 層次結構分為四層,App、Page、Item、Element。最外層為 App 層,一個 App 中包含一個 Page,Page 中包含一組 Item 元件(Item 可了解為一個長清單中的 Item),每個 Item 由多個 Element 構成。而 Element 就相當于萬花筒中的彩色碎片。

Element 分為多種類型,容器型允許互相嵌套,可包含子元素,可實作用簡單布局(如橫縱布局)組合出複雜的布局;元件型為最小元素,無子元素,不可再分;複合型可實作特殊布局和互動。

Kaleidoscope 資料格式采用了 JSON 格式,體積小,易生産,很通用;樣式布局描述系統采用了 Flexbox,RN 支援良好,布局能力強,學習成本低,其資料結構如下圖所示:

愛奇藝RN低代碼引擎:千變萬化、快速搭建的萬花筒

圖中左側為一個 JSON 結構,其中 Page 對象最重要的屬性為 Items 數組,單個 Item 由多個 contents 嵌套組成(圖中右側),再加上容器型 Element 中的 content,即可實作千變萬化的布局。

DSL 貫穿了 Kaleidoscope 方案,和 RN 堪稱天生一對:

JSON 結構和 RN 元件一一對應;

JSON Property 和 RN Prop 也一一對應;

RN 提倡組合大于繼承,适用 DSL 場景。

通過 RN 元件的設計和封裝,即可用一個簡潔的架構實作分而治之。

3

三、整體方案的架構設計

Kaleidoscope 整體架構圖分為前端、後端和低代碼平台三部分。前端面向内容消費者,後端和低代碼平台面向内容生産者以及部分開發人員。

愛奇藝RN低代碼引擎:千變萬化、快速搭建的萬花筒

前端架構中 Kaleidoscope 引擎處于下面架構圖的第二層,主要負責資料的下載下傳、緩存和解析,依賴于 QYRN 架構。QYRN 架構是愛奇藝以 RN 官方架構為基礎封裝的架構,它豐富了官方架構的元件庫,擴充了 UI 元件和原生子產品,實作了熱更新機制、資料投遞和 Bridge 執行個體複用。

愛奇藝RN低代碼引擎:千變萬化、快速搭建的萬花筒

後端架構如下所示。頁面資料來自于編輯們搭建頁面的配置資訊和内容原資料的資料流(虛線下的流程)。兩類資料一靜一動,會在不同端的 Worker Service 上融合,傳回給不同使用者端。

愛奇藝RN低代碼引擎:千變萬化、快速搭建的萬花筒

低代碼平台架構的核心為第三層 Portal,由兩塊組成:面向元件開發同學的元件開發平台和編輯使用的頁面可視化搭建平台。頁面可視化搭建平台實作完全零代碼,元件開發平台隻需要用少量代碼就可以開發元件,通常給外包人員使用。

愛奇藝RN低代碼引擎:千變萬化、快速搭建的萬花筒

4

四、萬花筒引擎的實作思路

RN 的動态性一直是其不容小觑的優勢。愛奇藝原生的 DSL 引擎也具有一定的動态性,可迅速實作界面更新、UI 改版等。基于 RN 和 DSL 強強結合,萬花筒引擎實作了引擎的高動态性。

同時,愛奇藝基于可嵌套容器實作了高布局靈活性。可嵌套容器為前述容器型 Element,此處不贅述了。我會重點介紹愛奇藝是如何基于 JS Card 實作高業務适應性、基于層疊實作低資料備援、基于依賴注入實作高擴充性的。

基于 JS Card 實作了高業務适應性

參考 HTML 中通過夾帶标簽編寫 JS 實作動态效果,為提高業務适應性,我們在 JSON 中也添加了 JS 腳本。針對無法用 JSON 描述的非通用需求場景,我們允許以 Card(清單項)為粒度直接用 RN 開發,打包成 JS 字元串之後和其他 JSON 資料一起下發,動态加載運作。Card 為前文中的 Item 被渲染後的帶界面的占有一定高度的實體。

JS Card 工作分為六步:

愛奇藝RN低代碼引擎:千變萬化、快速搭建的萬花筒

開發 JS Card。開發 JS Card 和開發 RN 元件唯一差别是需要将元件類存入 global 對象。

打包 JS 字元串。打包時需要注意雙引号轉義和包體積大小;

釋出 JS Card。在低代碼平台的元件開發平台建立一個 JS Card 元件,進行釋出;

接口傳回頁面資料。釋出後,端上請求接口即可擷取 JS 字元串,放入 DSL 配置對象的 base.script 屬性中,允許一個頁面中添加多個 JS Card;

解析執行 JS 注冊。引擎解析資料後,使用 eval 函數執行 JS 字元串,将字元串中定義的元件的 class 加到上下文中,從 global 中擷取對象并添加到 JS Card 系統資料庫中進行管理;

渲染。如 Item 有 ScriptID 屬性,則從 JS Card 系統資料庫中找到對應元件進行渲染。

基于層疊實作低資料備援

為了減少頁面中的備援資訊,愛奇藝基于 CSS 的層疊樣式表提出了層疊的概念,支援了資訊複用群組合,針對樣式資料提出了 Style 和 Theme,針對 pingback 資料提出了 Statistics 和 CommonStats。可在 Style 中引用 Theme,在 Statistics 引用 CommonStats,且支援按先後順序覆寫合成。

舉例來說,Style 可通過 ref 屬性引用 Theme 中定義好的類(如下圖左),引用了多個 Theme 可通過樣式繼承和覆寫機制合成具體的 Style(如下圖右)。

愛奇藝RN低代碼引擎:千變萬化、快速搭建的萬花筒

基于依賴注入實作高擴充性

不同業務方前來對接,但是需求不同時,愛奇藝采用了剝離核心功能,支援業務方按需裁剪、擴充和定制的思路。我們采用依賴注入的方式實作和使用所有的 Page、Item 和 Element 元件,打破了元件之間的強依賴。業務方可自由組合複用已有的元件,自定義元件,實作過程如下圖所示:

愛奇藝RN低代碼引擎:千變萬化、快速搭建的萬花筒

配置核心抽象類的具體依賴:這裡核心抽象類可分為 5 種:Pages、Services、Items、Elements、Components;

建立業務配置類:向架構注入 5 種核心抽象類執行個體配置;

引入業務配置類:在代碼入口注冊 App 元件;

引用舉例:在 App 元件中解耦引用注入的 listPage 元件。

5

五、低代碼平台設計與實作

下圖為愛奇藝編輯日常使用的頁面搭建系統:

愛奇藝RN低代碼引擎:千變萬化、快速搭建的萬花筒

左側為元件庫,中間為預覽區;右側為配置區。元件均為 Card 粒度,滑鼠拖動即可選中,在配置區即可配置 Card 的資料和樣式。

該平台擴充需要使用下圖中的元件開發平台添加元件、排版和樣式。

愛奇藝RN低代碼引擎:千變萬化、快速搭建的萬花筒

制作元件需寫一個描述該元件 UI 形式的 JSON 模闆。該 JSON 隻有内容占位符,具體内容需使用 Web IDE針對元件編寫一個 JS 函數來填充。該函數有四個輸入:元件 JSON 模闆内容、編輯搭建頁面時綁定的資料源對應的内容資料和填寫的标題等配置資訊、手機螢幕分辨率等需要參考的擴充資訊,傳回一個輸出:描述一個 Item 的 JSON 對象。這個 JS 函數跑在基于 Nashorn 的 JS 引擎上,外包稍加教育訓練便可編寫。

愛奇藝RN低代碼引擎:千變萬化、快速搭建的萬花筒

該平台面向多業務開放。業務申請開通後,開發後端的資料源即可利用愛奇藝現有元件搭建頁面,也可用低代碼平台開發元件。

6

六、性能優化

萬花筒引擎的性能優化實踐

我們在引擎上實作了懶加載(Inline Requires),當需使用子產品時再加載其資訊,提升了首屏加載性能。在 Android 端使用了 Hermes 引擎,性能優于 JSC。

針對引擎瘦身,我們實作了分包和精簡依賴,減少了 Bundle 體積和首屏加載耗時。愛奇藝衆多業務共享一個引擎,使用自研打包工具可将包含 RN 基礎功能的代碼剝離出去(大約 684KB),打出隻有業務代碼的 Bundle。精簡 NPM 依賴庫,可拆出不常用的元件,解除不必要的依賴。

愛奇藝RN低代碼引擎:千變萬化、快速搭建的萬花筒

JS Card 方面,我們在業務分包後再次分包,用自研的 JS Card 專用打包工具進行打包,将 JS Card 中萬花筒引擎自身已經包含的依賴庫在打包的時候剔除。經過層層分包愛奇藝已上線的 JS Card 如下圖所示,體積明顯下降。

7

七、開發、測試、調試、上線相關工具生态建設

在日常開發中,我們開發了一些工具,解決 DevOps 中的各種問題。

前端開發測試工具

我們開發了注冊制二維碼生成器,生成 RN 專題頁跳轉二維碼。掃碼後即可預覽,啟動 RN 的 JS 遠端調試工具後,即可調試引擎或 JS Card。注冊制是愛奇藝統一的參數化路由機制,如下圖所示,在頁面中設定專題頁參數,用愛奇藝 App 掃描生成的二維碼,即可打開對應的專題頁。

JS Card 品質監控

業務方開發的 JS Card 代碼問題不好定位。我們實作了 JS Card 運作時異常的捕獲和投遞,建設了統一的 JS Card 打包服務。利用該打包服務,可擷取所有 source map 檔案,可在愛奇藝的 APM 系統中還原崩潰棧中被混淆的 JS 代碼符号,效果如下所示:

愛奇藝RN低代碼引擎:千變萬化、快速搭建的萬花筒

端上捕獲投遞的原始 JS 崩潰棧(圖中左側),沒有詳細資訊。還原後(圖中右側)路徑檔案名詳細,便于問題診斷。

元件生态

内容上我們建設了模闆中心群組件市場。編輯搭建頁面時,挑選模闆中心中較合适的模闆稍加修改即可。

愛奇藝RN低代碼引擎:千變萬化、快速搭建的萬花筒

元件市場上業務方可貢獻自己的元件,複用已有的元件,共同建設元件生态。

愛奇藝RN低代碼引擎:千變萬化、快速搭建的萬花筒

8

八、上線效果和經驗總結

Kaleidoscope 方案先後在愛奇藝、随刻、愛奇藝票務、愛奇藝小說共 4 款 App 上落地,在 GPhone、iPhone、iPad 三端總 UV 峰值過億,主要應用于首頁頂導航特色專題、一般專題、播單、會員權益等 4 個場景,這些場景各有特點:

在首頁頂導航特色專題頁上,實作了兩個 RN 專題頁之間切換效果;導航欄背景色可随着切換頁面而變化,為使用者帶來沉浸式體驗;

在會員頂導航專題頁上,大量定制化 JS Card 元件實作了衆多個性化需求,例如:吸頂導航元件,可以滾動頁面到指定的 Item;

在播單上,實作了播放器根據頁面滾動位置自動開播,一個視訊播放完畢後自動滾動到下一個視訊自動開播等進階互動特性;

在一般專題上,無需引擎疊代,即可快速搭建、上線頁面。

從 2018 年 12 月正式全量上線,Kaleidoscope 穩定運作至今 2 年半左右,在 GPhone、iPhone、iPad 三端總共上線過 1297 個專題頁,平均 1 天 1.4 個,最近 30 天愛奇藝 Phone 端上線了 63 個頁面,平均搭建時長 19.25 分鐘。

在這個過程中RN+DSL+JS Card 方案滿足了各類需求,且幾乎不需要跟版;得益于 RN 跨平台特點和簡潔靈活的架構設計,萬花筒引擎開發和維護成本極低;引擎每次變更都經過代碼評審,保證了線上持久穩定運作。

同時,我們發現JS Card 是一把雙刃劍,由于開發權外放,要注意性能,并進行治理;DSL 和引擎不斷疊代會帶來一些前後端相容性問題,需要引入較為複雜的版本管理機制;另外,新老架構過渡替換也會帶來的一系列問題,我們通過多輪灰階進行規避。

嘉賓介紹

甘泉

2016 年底加入愛奇藝,先後從事過 RN 架構開發,RN 架構、Flutter 架構、小程式架構、WebView 容器優化和開發團隊管理,目前擔任 App 中台團隊負責人。在跨平台開發架構優化和應用方面具有豐富經驗,在 App 中台建設方面也有一些心得。

活動推薦

繼續閱讀