代碼復用率99%,攜程市場洞察平臺Donut跨多端高性能技術實踐
作者簡介
Brain,攜程高級軟件技術專家,關注前端技術框架、跨端技術方案、前端構建和工程化工具,致力于前沿技術和架構優化。
一、背景
FlightAI(市場洞察平臺)是攜程機票大數據團隊推出的一款賦能行業的toB數據產品。FlightAI的用戶群主要使用微信,但也有移動端和其他企業辦公IM系統(如企業微信、釘釘等)的使用需求。由于大數據團隊的前端工程師人數很少,且現有技術棧主要是web技術,缺乏移動端開發經驗,因此需要選擇一種以微信為主、研發成本低、跨平臺(微信小程序、iOS、Android)應用的技術,以滿足業務需求并提升研發效率。
FlightAI涉及大型表格操作與展示、大數據的圖表繪制、大數據量數據指標呈現等場景,對查詢和展示渲染性能要求較高。此外,還需要在微信公眾號、web系統、小程序、移動端等多維度產品矩陣中實現業務功能、用戶登錄注冊、賬號管理與體系打通,形成立體式產品服務,以提升用戶體驗和運營效率。
1.1 難點與挑戰
1.1.1 主要難點
a. 跨平臺開發的復雜性:
- 雖然一些框架如React Native,Flutter,Weex等同構了iOS、Android的架構,但在獨立完成移動端全流程開發和基礎設施建設上,仍面臨技術棧多樣性的問題,特別是跨端架構中還需優先支持小程序。
- 需要掌握不同平臺(iOS、Android、微信小程序)的證書管理、腳本命令調用、法律法規提示和約束差異、真機和模擬器開發、調試、構建、發布技術。
- 跨平臺兼容性問題,如日歷優化中遇到樣式兼容性,性能問題等,需要深入理解各平臺的差異和限制。
- 不同平臺、不同流程下各種Token、認證和法律法規限制概念較多,較難分清。
- UI組件在各平臺的兼容性、生命周期管理和權限系統、SDK稍有差異,一旦發生bug識別出這種差異較有難度。
b. 多端登錄態打通:
- 需要解決不同平臺間的登錄態同步問題,確保用戶在不同設備和平臺上有一致的體驗。
- 不同端的登錄支持方式多樣,需要做好同構和異構,如APP端需支持本機號碼一鍵登錄、賬號登錄、小程序登錄、微信登錄、蘋果登錄等,以支持各個平臺的審核。
- Token種類非常多且復雜,各自用途不同,涉及前臺與服務端code交換和token驗證等邏輯。
c. 大數據列表渲染支持:
- 小程序雙線程機制導致涉及交互的大數據列表渲染性能優化成為難題。
- 在小程序的技術架構下,官方支持最大DOM數是16000個,text類節點也被計算在總節點數中,容易超過DOM數限制,導致"Dom limit exceeded"錯誤。
1.1.2 新技術平臺的挑戰
a. 功能覆蓋率:
- 雖然官方號稱跨多端,但功能覆蓋率、API覆蓋率是否足夠,接入是否復雜,能否滿足當前和未來的需求?
b. 基礎設施:
- 研發工具、測試工具、部署工具、運維工具是否成熟,遇到問題如何快速找到支持和解決方案?
c. 研發生態兼容性:
- 除了大的跨端技術框架面臨挑戰,落地實施會面臨更多小型技術選型的挑戰,如組件系統、圖表庫、其他平臺支持、兼容性問題。
1.2 技術選型
1.2.1 業務需求與現狀
a. 團隊規模小,跨多端需求和高研發效率需求:
- 小型研發團隊,現有技術技能主要是JS技術棧,缺乏移動端開發經驗,必須控制培訓成本和研發成本;
- 考慮集成難度和行業趨勢,分析功能需求和性能需求等,FlightAI用戶有強烈的移動端使用需求,僅開發小程序無法滿足;
- 需要選擇一款技術復雜度低、研發成本低、技術棧簡單的跨平臺框架,而Donut技術滿足跨多端、高性能、低成本需求,且有騰訊官方支持;
b. 業務需求:
- 建立獨立賬號體系、獨立域名和品牌,要求與微信公眾號、web系統體系化運營,形成產品矩陣;
- 微信小程序在功能和性能上都要求高優先級支持;
c. 高性能需求:
- Donut在小程序支持度和App性能上表現優異。在App上底層基于Flutter,使用和微信小程序相同的一套容器,接近原生渲染性能;
- FlightAI具有大批量數據實時渲染的需求,對渲染性能要求很高;與公司框架計劃支持使用Flutter提升渲染性能的技術路線一致;
1.2.2 為何選型Donut技術
由于用戶群體主要以微信小程序為主要使用場景,所以無法支持小程序的多端框架如React Native,Flutter等無法選用,而既支持小程序又支持移動端的技術框架,目前市面比較流行的是taro和uni-app,但存在如下顧慮:
- 使用該類框架后,功能更新完全依賴于框架,微信小程序里有的功能可能無法支持;
- 使用該類框架后,代碼經過二次轉換,性能可能不如原生WXML,而且會帶入轉換邏輯額外引入的代碼和性能憂慮;
- 該類框架一般都會自定義DSL,有一定的學習成本,文檔是否健全,社區支持是否完善將直接影響配置和自定義功能的效率;
- 該類框架優勢多在跨多端小程序,實際上線APP的案例并不多,大坑小坑無法避免,例如uniapp的nvue原生開發有局限性,特別是樣式方面限制比較嚴重;
- 跨多端應用開發的全生命周期集成和管理能力是否強大,包括開發,測試,構建,發布,運維,法律法規提示與解讀,token管理等;
而Donut是騰訊官方推出的和小程序同源容器,在功能和性能上比這類衍生框架更優秀,在App上底層基于Flutter,接近原生渲染性能;Donut以小程序DSL作為開發語言,可以無縫切換,也沒有二次轉換的成本,會開發小程序就會寫Donut APP。在研發工具、測試工具、部署工具、運維工具上騰訊做了全方位集成,小型團隊可能遇到的問題幾乎全部涵蓋。官方文檔一步一截圖,閱讀體驗良好,總結如下:
a. 功能覆蓋率較高
常用需要適配API(8個),根據使用情況進行選擇支持,Donut官方提供了非常多的功能API,從功能支持度、易用性和架構上App小程序同構上也可以看出官方的大力投入。
JSAPI 和組件支持匯總,涉及6大方面
組件部分:視圖組建,表單,導航,媒體,地圖,畫布,開發能力,原生組建都能較好支持;
API部分支持情況:總共大概507個API;支持371個,大概占73%,部分支持或者不支持的部分官方提供一些其他的替代方案;(2024-03統計)
SDK部分:基礎SDK和擴展SDK支持較好;這部分是Native功能,根據需要進行勾選,不選就不會打入包中,按需打包降低包size;
NativePlugin:支持Native自定義擴展,該部分都是一次性工作,除非有強烈的自定義需求,一般都用不上;
云支持:云開發云托管,Donut網關防護;
埋點監控:熱力圖,回放功能支持完善,支持全埋點;
b.基礎設施較完善
Donut 平臺覆蓋開發、部署、產品體驗分析全產品開發周期的各種需求,研發工具、測試工具、部署工具、運維工具上騰訊做了全方位集成,基礎設施比較完善,貫穿產研全流程支持,可大幅提升研發效率,特別對于沒有移動端研發經驗的團隊具有引導和指導的作用。
- 多端框架-支持使用小程序原生語法進行一次代碼編寫,多端編譯,實現多端開發。
- 多端身份管理-幾行代碼,快速實現 App、小程序的身份認證和用戶管理。
- 安全網關-提供弱網加速、防爬防刷、流量治理等能力,全方位保障業務安全高效穩定運行。
- 產品體驗分析-從真實的用戶視角洞察產品問題,尋找產品體驗的不足之處,提升用戶留存與轉化,具有如下功能:
- 零代碼、全埋點
無需開發,一鍵接入,元素自動全埋點,快速開始小程序數據分析。 - 還原用戶操作現場
創新可視化日志 & 熱力圖,還原用戶實際操作現場,問題分析一目了然。 - 可視化交互分析
全程無需 SQL 編寫,僅需在模擬器上點選交互即可完成分析過程。 - 一鍵智能分析
無需數據分析背景,根據業務目標智能分析,查找用戶漏點,提升轉化率。
c. 研發生態兼容性較強
- UI組件系統
UI組件系統選型TDesign還是使用WeUI,還是使用Ant Design for Mobile,NutUI,Vant,Material-UI?
主要考慮組件的成熟度,兼容性,組件功能,TDesign是騰訊官方出品的組件庫,而WeUI則側重提供樣式庫,考慮社區實踐經驗,最終選擇TDesign,組件相對豐富,常用組件齊全,貼合微信設計規范,在Donut APP的兼容性較好,復用組件可以節省不少開發工作量。
- 圖表庫選擇
圖表庫使用echart還是g2移動版圖表庫,還是選擇wx-chart,ucharts,D3,antV,Threejs等圖表庫?從如下幾個方面進行了考慮:代碼規范:EChart、D3官網的部分案例還是使用了ES5的語法,Antd遵循了ES6新語法規范。靈活度:ECharts<G2<D3;使用難度:Echart≈G2PLot<G2<D3;場景:三維圖推薦用Threejs,二維圖用ECharts或者G2、G2Plot均可;考慮到FlightAI圖表類型為常規圖形,而且PC版本選型也是Echart,在小程序集成和兼容性上,Echart都表現較好,但Echart在分辨率處理上和Donut系統并不兼容,但在編寫適配層解決該難題后,用起來非常絲滑,所以最終選定Echart。
- 小程序兼容性
小程序轉其他小程序或者web的方案調研如morjs等轉出來的小程序,其他跨多端如Taro轉Donut技術是否可行?
理論上Donut提供的是小程序運行容器,其他跨端或者轉換技術只要最終產物符合微信小程序規范,應該可以運行,但是轉換必然導致功能和性能上有損耗,而且對于Donut條件編譯等語法需要進行特殊處理,一般轉換代碼會帶來額外的處理邏輯,會增大包Size,雖然有副作用,但Donut本身的擴展能力還是很強的,畢竟提供了和微信一致的小程序容器。
1.3 Donut簡介
Donut平臺是騰訊出品的基于小程序實現跨多端(小程序,IOS,Andord)的技術體系,覆蓋了開發、部署、產品體驗分析全產品開發周期的各種需求。開發者可以專注于代碼邏輯,將復雜的開發構建流程,開發及運行環境等統一管理,有效降低多端應用開發的技術門檻和研發成本,以及提升開發效率和開發體驗。包含4大特色能力:多端框架,多端身份管理,安全網關,產品體驗分析。
1.3.1 Donut系統模塊圖:
主要分為客戶端和云端功能,客戶端主要負責端側的標注化容器,處理小程序基礎庫,小程序SDK等基礎設施,云側主要處理各種管理和審核功能,流程都集成在了微信開放平臺,微信開發者平臺,微信公眾平臺,Donut管理平臺幾大平臺上。
1.3.2 Donut工作流程
簡單理解,就是微信抽象了一個簡化版本的微信APP作為容器,底層都是基于Flutter進行渲染,承接小程序的能力,并利用微信開發者工具提供研發支持;理論上只要是微信小程序都能運行在該平臺上。
1.3.3 Donut技術適合誰
a. 基于小程序生態開展業務的個人或企業;
b. 需要跨多端支持、高性能和高研發效率的項目;
c. 已經擁有小程序,想擴展到移動端的項目;
d. 希望簡化或標準化開發運營流程,利用微信提供的全軟件研發周期集成能力的項目。
二、FlightAI如何基于小程序構建一款跨多端移動應用Donut-APP
首先在微信公眾平臺(mp.weixin.qq.com)注冊小程序,完成注冊后可同步進行信息完善和開發。下載微信開發者工具、參考開發文檔進行開發和調試。要成為Donut跨多端研發人員需要了解如下信息:
2.1 多端應用開發:開發賬號準備
2.2 了解賬號關系
2.3 多端應用開發:開發資源準備
2.4 開啟多端應用模式
a. 新建或者升級小程序為多端項目即可
b. Donut多端項目結構
和小程序項目結構一致,只是多了一些跨多端框架的配置文件,app.miniapp.json主要作用是維護多端應用和小程序綁定關系,配置App小程序登錄頁面地址,授權頁等。
project.miniapp.json則主要用于配制原生插件,多和native交互有關;project.config.json則是小程序相關的配置文件。
2.5 了解條件編譯
Donut支持以條件編譯的方式編寫特定平臺代碼;如有些組件只有微信支持,有些業務需求只在微信展示,那么就需要條件編譯實現差別需求,在app上和小程序使用不同的代碼方式實現,一般該類代碼占比較少,FlightAI項目中,我實現了自動統計條件編譯代碼的功能,可統計上報或者單機運行了解項目狀態。
2.6 多種登錄方式支持-多端身份管理
a.FlightAI登錄架構設計
Donut支持多種登錄方式,一般項目完全夠用了,并在后臺做了較好的集成管理,官方叫做多端身份管理,FlightAI的場景比較復雜,除了Donut提供的5登錄方式之外,還支持了密碼登錄等總共10種登錄方式,給客戶最大的便利和可選擇性;支持方式多樣,但是底層驗權,鑒權,授權等接口都實現了統一。
b.小程序和 App 的統一身份識別
小程序的token和code2Session接口進行交換,App的token和code2Verifyinfo接口進行交換,各個接口都有配套API,比較復雜,不能搞混了,最好單獨一整套接完,再接入另外一套。
2.7 大列表渲染
在webview的雙線程架構下,小程序的官方支持最大Dom數是16000個,text類節點也被計算在總節點數中,非常容易就超過Dom數限制,導致Dom limit exceeded, please check if there's any mistake you've made.
無論是模擬器還是真機,小程序還是Donut APP,在FlightAI場景中view-all頁面,經過測試442條渲染Item是臨界點,超過442條就會白屏,在該數據結構下Dom數會達到臨界點,并且442條數據在IOS模擬器上渲染耗時5646ms,這也側面證實了各端各工具在Dom數限制上是一致的。
官方推薦標準
官方推薦說明(也是評分標準),單頁面節點盡量不超過1000個節點,嵌套不超過30層,子節點不超過60個,頁面深度不超過10個;但功能較為復雜的頁面,非常容易就超出限制,那么如何突破這個問題呢?
長列表渲染特點
1)列表數據很大,首次 setData 的時候耗時高,雙線程模型使得交互性能成為瓶頸;
2)一次渲染出來的列表 DOM 結點多,每次 setData 都需要創建新的虛擬樹、和舊樹 diff 操作耗時都比較高;
3)渲染出來的列表 DOM 結點總數多,占用的內存高,造成頁面被系統回收的概率變大。
優化思路
要么徹底改變雙線程的底層架構,要么通過一些手段優化參與渲染的數據和狀態,只渲染顯示在屏幕的數據,基本實現就是監聽 scroll 事件,并且重新計算需要渲染的數據,不需要渲染的數據留一個空的 div 占位元素。如下是2個解決方案:
a.微信官方提供recycle-view的解決方案,虛擬列表方案;
在滾動過程中,重新渲染數據的同時,需要設置當前數據的前后的 div 占位元素高度,同時是指在同一個渲染周期內。頁面渲染是通過 setData 觸發的,列表數據和 div 占位高度在2個組件內進行 setData 的,為了把這2個 setData 放在同一個渲染周期,用了一個 hack 方法,所以定義 recycle-view 的 batch 屬性固定為 batch="{{batchSetRecycleData}}"。
b.微信官方為提升渲染速度,開發了skyline渲染引擎。
skyline渲染引擎,使用更精簡高效的渲染管線,并帶來諸多增強特性,讓 Skyline 擁有更接近原生渲染的性能體驗。
使用skyline之后,不會有dom數限制了;而且很明顯的一個對比是使用skyline后,快速滑動長列表不卡頓,首頁沒有開啟skyline快速滑動會卡頓。
注意列表布局容器,僅支持作為 scroll-view 自定義模式下的直接子節點或組件直接子節點,scroll-view要設置自定義模式 type="custom",list-view要作為 scroll-view 直接子節點。
WebView 的 JS 邏輯、DOM 樹創建、CSS 解析、樣式計算、Layout、Paint (Composite) 都發生在同一線程,在 WebView 上執行過多的 JS 邏輯可能阻塞渲染,導致界面卡頓。
Skyline 創建了一條渲染線程來負責 Layout, Paint 和 Composite等渲染任務,并在 AppService 中劃出一個獨立的上下文,來運行之前 WebView 承擔的 JS 邏輯、DOM 樹創建等邏輯,架構深度優化后性能提升顯著。
Skyline長列表官方文檔
性能對比
官方示例:小程序助手的線上數據,可以看出 Skyline 的首屏時間比 WebView 快 66%,并且手機性能越低端,差異就越明顯。
另外嘗試自行計算小程序的Dom數,Dom層級,做統計或者優化,發現querySeletorAll API無法使用通配符,另外涉及到Shadow-Dom,計算變得非常麻煩;向微信官方求證過Dom最大size的數量是16000個,這是編譯器層面的限制,無法放開。經過和微信官方溝通結果是他們可以提供小程序的Dom數計算API,目前還沒有提供,將來可以提供。
2.8 實現Push消息推送
FlightAI接入TPNS或者公司的Push系統的一些思考和調研;騰訊云有提供TPNS,但是這套推送接入成本較高,而且已停止售賣;收費標準大概是800*DAU/10000,8分錢/條,按用戶收費。
Donut提供了基于IM的新版本推送服務,2024-8月份開始支持;通過配置插件和證書實現推送功能,支持在線推送和離線推送;IOS和Android的各個廠商需要分別進行配置,這是廠商的規范不同導致。
新版本收費規則根據數據中心位置和不同的套餐有所不同。后臺需要根據各廠商申請對應的證書AppKey和AppID,并根據需求制定推送策略。
對于接入成本的考慮,在客戶端只需簡單配置PluginId即可,配置示例:
2.9 正式構建APK和IPA
構建移動端APP的臨時簽名和正式簽名是區分的,臨時簽名Donut官方直接提供,正式簽名證書,需要研發人員按照目標平臺進行注冊,上傳,注意簽名文件對目錄有要求,必須放在項目內,IOS的鑰匙串必須和配置中的名稱完全一致。
2.10 內測分發與提交審核
在開發者工具上 選擇 正式版點擊「構建」- 「上傳資源包」,即可將開發版本的資源包上傳至Donut資源包管理平臺,之后跟進研發流程自行決定測試版本和線上版本。
2.11 完成各平臺隱私協議,法律條款,授權彈窗等上架要求,發布APP
需要注意的是各大電子市場的要求各不相同,為了能夠上架,需要滿足各平臺的各種規范,否則審核無法通過,特別是涉及法律條款需要法務部門介入,通常時間非常長,要做好相關準備。
2.12 踩了哪些坑
- 一些證書導致的問題
在進行基礎設施建設中,完成小程序,Donut跨多端基建,包括環境搭建、系統配置、開發、測試和發布流程的打通, 技術框架搭建,架構設計模型,開發流水線等。比如證書位置不對,證書信息不匹配,申請證書的Domain,link等信息不一致,在構建的時候可能會報一些奇怪的錯誤,始終無法通過構建,這塊的研發信息提示很不明確,但會Block研發進程,已建議官方優化; - 構建產物,雖然功能增多,業務邏輯變的越來越復雜,包size會正常增長,但是如果有自定義管理資源包的需求,那么就會遇到包size上傳限制的問題,那么就需要分包,比如我們nephle最大支持30M的包,需要解決分塊上傳問題;另外如果要實現ios自動下載安裝的能力,模版地址和包地址需要放在同一目錄,否則坑較深,會浪費不少精力和時間;另外真機調試和構建,直連的數據線非常重要,帶轉換的多功能數據線很有可能帶來不少意外的構建問題;
- 功能開發與性能優化:圖表功能開發,日歷功能開發與性能優化,TDesign官方日歷組件存在性能問題,官方提供的format鉤子,在遇到多年份日期遍歷的時候,性能問題突出,t-calendar并且不支持虛擬列表,所以性能不理想,采用Hash算法后優化了近400倍,提升日歷功能的性能,另外TDesign和Donut是不同的團隊,提issue的時候要找準團隊,否則可能不被受理。
- 小程序備案,域名備案,微信認證,用戶告知,服務條款,隱私協議,軟著商標,何時啟動?有哪些坑?
法務審核和各種認證需要準備很多企業實體資料,盡早準備提交,完全按照文檔操作,否則會被打回重寫,再者審核周期不可控,應當盡早啟動,隱私彈窗和授權彈窗必須使用模版或者native開發,不能使用其他方式,因為APP在授權之前是不能加載和運行代碼的。請仔細閱讀相關章節注意事項; - token管理
token是測試一套,生產一套,配置不同,Android和IOS平臺各自管理一套,另外mobileprovision必須包含Doman,而且Donut和開發工具,APP中的信息必須一致;
三、成果與經驗
3.1 技術創新與效率提升,代碼復用率99%
- 代碼復用率:實現了99%的代碼復用率,特定平臺代碼代碼為非復用代碼,自行實現了自動統計的功能;
- 成功研發一款跨平臺高性能APP:成功開發了業務代碼基于小程序,底層框架與微信同源基于Flutter的高性能跨多端移動應用,確保iOS、Android和微信小程序上的一致性和高性能,為公司探索新跨多端技術方案;搭建了iOS和Android應用的自動化構建和持續集成(CI/CD)管道,提升了開發和發布效率;
- 采用Skyline新渲染引擎, 首屏時間比 WebView 快 66%,更重要的是Skyline沒有Dom數限制,對于開發大型項目來說非常重要;
- 一碼多端,跨多端真機效果;
3.2 打造產品矩陣,用戶體驗
為了提升攜程市場洞察平臺的應用范圍和市場競爭力,我們打造了一個全面的產品使用矩陣,實現了移動端、小程序、現有的Web端、微信公眾號和API服務的完整覆蓋。通過這種多端覆蓋,我們能夠更好地滿足用戶在不同場景下的使用需求,提升產品的市場競爭力。
為了提升用戶體驗,我們打通了多種設備和多種類型的登錄態,支持用戶通過不同設備和渠道無縫登錄。除了Donut提供的5登錄方式之外,還支持了密碼登錄等總共10種登錄方式,給客戶最大的便利和可選擇性。
在市場洞察平臺中基于Donut實現了跨多端高性能移動端的技術實踐,確保了產品在各種移動場景下的優異表現。
通過這些技術創新和優化,我們不僅提升了產品的應用范圍和市場競爭力,還顯著改善了用戶體驗,為用戶提供了更加便捷和高效的使用體驗。