「道生一,一輩子二,二生三,三生萬物。」 —— 《道德經》
複製代碼
Picasso是大衆點評移動研發團隊自研的高性能跨平臺動態化框架,通過兩年多的孕育和發展,目前在美團多個事業羣已經實現了大規模的應用。前端
Picasso源自咱們對大前端實踐的從新思考,以簡潔高效的架構達成高性能的頁面渲染目標。在實踐中,甚至能夠把Native技術向Picasso技術的遷移當作一種性能優化手段;與此同時,Picasso在跨越小程序端和Web端方面的工做已經取得了突破性進展,有望在四端(Android、iOS、H五、微信小程序)統一大前端實踐的基礎之上,達成高性能大前端實踐,同時配合Picasso佈局DSL強表達能力和Picasso代碼生成技術,能夠進一步提高生產力。android
2007年,蘋果公司第一代iPhone發佈,它的出現「從新定義了手機」,並開啓了移動互聯網蓬勃發展的序幕。Android、iOS等移動技術,打破了Web應用開發技術即將一統江湖的局面,以後海量的應用如雨後春筍般涌現出來。移動開發技術給用戶提供了更好的移動端使用和交互體驗,但其「靜態」的開發模式卻給須要快速迭代的互聯網團隊帶來了沉重的負擔。git
客戶端開發技術與Web端開發技術相比,天生帶有「靜態」的特性,咱們能夠從空間和時間兩個維度來看。github
從空間上看須要集成發佈,美團App承載業務衆多,是跨業務合流,橫向涉及開發人員最多的公司,雖然開發人員付出了巨大的心血完成了業務間的組件化解耦拆分,但依然無可避免的形成了如下問題:編程
從時間上看須要集中發佈,線上Bug修復鬚髮版或熱修復,成本高昂。新功能的添加也必須等待統一的發版週期,這對快速成長的業務來講是不可接受的。App開發還面臨嚴重的長尾問題,沒法爲使用老版本的用戶提供最新的功能,嚴重損害了用戶和業務方的利益。小程序
這種「靜態」的開發模式,會對研發效率和運營質量產生負面影響。對於傳統的桌面應用軟件開發而言,靜態的研發模式也許是相對能夠接受的。但對於業務蓬勃發展的移動互聯網行業來講,靜態開發模式和敏捷迭代發佈需求的矛盾日益突出。微信小程序
如何解決客戶端「靜態」開發模式帶來的問題?瀏覽器
業界最先給出的答案是使用Web技術性能優化
但Web技術與Native平臺相比存在性能和交互體驗上的差距。在一些性能和交互體驗能夠妥協的場景,Web技術能夠在定製容器、離線化等技術的支持下,承載運營性質的須要快速迭代試錯的頁面。bash
另外一個業界給出的思路是優化Web實現
利用移動客戶端技術的靈活性與高性能,再造一個「標準Web瀏覽器」,使得「Web技術」同時具備高性能、良好的交互體驗以及Web技術的動態性。此次技術浪潮中Facebook再次成爲先驅,推出了React Native技術(簡稱RN)。不過RN的設計取向有些奇怪,RN不兼容標準Web,甚至不爲Android、iOS雙端行爲對齊作努力。產生的後果就是全部「吃螃蟹」的公司都須要作二次開發才能基本對齊雙端的訴求。同時還須要盡最大努力爲RN的兼容性問題、穩定性問題甚至是性能問題買單。
而咱們給出的答案是Picasso
Picasso另闢蹊徑,在實現高性能動態化能力的同時,還以較強的適應能力,以動態頁面、動態模塊甚至是動態視圖的形式融入到業務開發代碼體系中,贏得了許多移動研發團隊的認同。
Picasso框架跨Web端和小程序端的實踐也已經取得了突破性進展,除了達成四端統一的大前端融合目標,Picasso的佈局理念有望支持四端的高性能渲染,同時配合Picasso代碼生成技術以及Picasso的強表達能力,生產力在大前端統一的基礎之上獲得了進一步的提高。
Picasso應用程序開發者使用基於通用編程語言的佈局DSL代碼編寫佈局邏輯。佈局邏輯根據給定的屏幕寬高和業務數據,計算出精準適配屏幕和業務數據的佈局信息、視圖結構信息和文本、圖片URL等必要的業務渲染信息,咱們稱這些視圖渲染信息爲PModel。PModel做爲Picasso佈局渲染的中間結果,和最終渲染出的視圖結構一一對應;Picasso渲染引擎根據PModel的信息,遞歸構建出Native視圖樹,並完成業務渲染信息的填充,從而完成Picasso渲染過程。須要指出的是,渲染引擎不作適配計算,使用佈局DSL表達佈局需求的同時完成佈局計算,既所謂「表達即計算」。
從更大的圖景上看,Picasso開發人員用TypeScript在VSCode中編寫Picasso應用程序;提交代碼後能夠經過Picasso持續集成系統自動化的完成Lint檢查和打包,在Picasso分發系統進行灰度發佈,Picasso應用程序最終以JavaScript包的形式下發到客戶端,由Picasso SDK解釋執行,達成客戶端業務邏輯動態化的目的。
在應用程序開發過程當中,TypeScript的靜態類型系統,搭配VSCode以及Picasso Debug插件,能夠得到媲美傳統移動客戶端開發IDE的智能感知和斷點調試的開發體驗。Picasso CI系統配合TypeScript的類型系統,能夠避免低級錯誤,助力多端和多團隊的配合;同時能夠經過「兼容計算」有效的解決能力支持的長尾問題。
Picasso針對移動端主流的佈局引擎和系統作了系統的對比分析,這些系統包括:
其中蘋果官方推出的AutoLayout缺少一個好用的DSL,因此咱們直接將移動開發者社區貢獻的 AutoLayout DSL方案列入對比。
首先從性能上看,AutoLayout系統是表現最差的,隨着需求複雜度的增長「佈局計算」耗時成指數級的增加。FlexBox和LinearLayout相比較AutoLayout而言會在性能表現上有較大優點。可是LinearLayout和FlexBox會讓開發者爲了佈局方面須要的概念增長沒必要要的視圖層級,進而帶來渲染性能問題。
從靈活性上看,LinearLayout和FlexBox佈局有很強的概念約束。一個強調線性排布,一個強調盒子模式、伸縮等概念,這些模型在佈局需求和模型概念不匹配時,就不得不借助編程語言進行干預。而且因爲佈局系統的隔離,這樣的干預並不容易作,必定程度上影響了佈局的靈活性和表達能力。而配合基於通用編程語言設計的DSL加上AutoLayout的佈局邏輯,能夠得到理論上最強的靈活性。可是這三個佈局系統都在試圖解決「用聲明式的方式表達佈局邏輯的問題」,基於編程語言的DSL的引入讓佈局計算引擎變得多餘。
Picasso佈局DSL的核心在於:
使用錨點概念能夠簡單清晰的設置非同一個座標軸方向的兩個錨點「錨定」好的視圖位置。同時錨點能夠提供描述「相對」位置關係語義支持。事實上,針對佈局的需求更符合人類思惟的描述是相似於「B位於A的右邊,間距10,頂對齊」,而不該該是「A和B在一個水平佈局容器中……」。錨點概念經過極簡的實現消除了需求描述和視圖系統底層實現之間的語義差距。
下面舉幾個典型的例子說明錨點的用法:
1 居中對齊:
view.centerX = bgView.width / 2
view.centerY = bgView.height /2
複製代碼
2 右對齊:
view.right = bgView.width - 10
view.centerY = bgView.height / 2
複製代碼
3 相對排列:
viewB.top = viewA.top
viewB.left = viewA.right + 10
複製代碼
4 「花式」佈局:
viewB.top = viewA.centerY
viewB.left = viewA.centerX
複製代碼
Picasso錨點佈局邏輯具備理論上最爲靈活的的表達能力,能夠作到「所想即所得」的表達佈局需求。可是有些時候咱們會發如今特定的場景下這樣的表達能力是「過剩的」。相似於下圖的佈局需求,須要水平排布4個視圖元素、間距十、頂對齊;可能會有以下的錨點佈局邏輯代碼:
v1.top = 10
v1.left = 10
v2.top = v1.top
v3.top = v2.top
v4.top = v3.top
v2.left = v1.right + 10
v3.left = v2.right + 10
v4.left = v3.right + 10
複製代碼
顯然這樣的代碼不是特別理想,其中有較多可抽象的重複的邏輯,針對這樣的需求場景,Picasso提供了hlayout佈局函數,完美的解決了水平排布的問題:
hlayout([v1, v2, v3, v4],
{ top: 10, left: 10, divideSpace: 10 })
複製代碼
有心人能夠發現,這和Android平臺經典的LinearLayout一模一樣。對應hlayout函數的還有vlayout,這一對幾乎完整實現Android LinearLayout語義的兄弟函數,實現邏輯不足300行,這裏強調的重點其實不在於兩個layout函數,而是Picasso佈局DSL無限制的抽象表達能力。若是業務場景中須要相似於Flexbox或其餘的概念模型,業務應用方均可以按需快速的作出實現。
在性能方面,Picasso錨點佈局系統避免了「聲明式到命令式」的計算過程,徹底無需佈局計算引擎的介入,達成了「需求表達即計算」的效果,具備理論上最佳性能表現。
因而可知,Picasso佈局DSL,不管在性能潛力和表達能力方面都優於以上佈局系統。Picasso佈局DSL的設計是Picasso得以構建高性能四端動態化框架的基石。
同時得益於Picasso佈局DSL的表達能力和擴展能力,Picasso在自動化生成佈局代碼方面也具備得天獨厚的優點,生成的代碼更具備可維護性和擴展性。伴隨着Picasso的普及,當前前端研發過程當中「視覺還原」的過程會成爲歷史,前端開發者的經歷也會從「複製」視覺稿的重複勞動中解脫出來。
業界對於動態化方案的期待一直是「接近原生性能」,可是Picasso卻作到了等同於原生的渲染效率,在複雜業務場景能夠達成超越原生技術基本實踐的效果。就目前Picasso在美團移動團隊實踐來看,同一個頁面使用Picasso技術實現會得到更好的性能表現。
Picasso實現高性能的基礎是宿主端高效的原生渲染,但實現「青出於藍而勝於藍」的效果卻有些反直覺,在這背後是有理論上的必然性的:
Picasso的錨點佈局讓 佈局表達和佈局計算同時發生。避免了冗餘反覆的佈局計算過程。
Picasso的佈局理念使 視圖層級扁平。全部的視圖都各自獨立,沒有爲了佈局邏輯表達所產生的冗餘層級。
Picasso設計支持了 預計算的過程。本來須要在主線程進行計算的部分過程能夠在後臺線程進行。
在常規的原生業務編碼中,很難將這些優化作到最好,由於對比每一個小點所帶來的性能提高而言,應用邏輯複雜度的提高是不能接受的。而Picasso渲染引擎,將傳統原生業務邏輯開發所能作的性能優化作到了「統一複用」,實現了一次優化,全線受益的目標。
Picasso跨平臺高性能動態化框架在集團內部發布後,獲得了普遍關注,集團內部對於客戶端動態化的方向也十分承認,積極的在急需敏捷發佈能力的業務場景展開Picasso應用實踐;通過大概兩年多的內部迭代使用,Picasso的可靠性、性能、業務適應能力受到的集團內部的確定,Picasso動態化技術獲得了普遍的應用。
經過Picasso的橋接能力,基於Picasso的上層應用程序仍然能夠利用集團內部移動技術團隊積累的高質量基礎建設,同時已經造成初步的公司內部大生態,多個部門已經向Picasso生態貢獻了動畫能力、動態模塊能力、複用Web容器橋接基建能力、大量業務組件和通用組件。
Picasso團隊除了持續維護Picasso SDK,Picasso持續集成系統、包括基於VSCode的斷點調試,Liveload等核心開發工具鏈,還爲集團提供了統一的分發系統,爲集團內部大前端團隊開展Picasso動態化實踐奠基了堅實的基礎。
到發稿時,集團內部Picasso應用領先的BG已經實現Picasso動態化技術覆蓋80%以上的業務開發,相信通過更長時間的孵化,Picasso會成爲美團移動開發技術的「神兵利器」,助力公司技術團隊實現高速發展。
列舉Picasso在美團的部分應用案例:
Picasso在實踐客戶端動態化的方向取得了成功,解決了傳統客戶端「靜態」研發模式致使的種種痛點。總結下來:
至此Picasso並無中止持續創新的腳步,目前Picasso在Web端和微信小程序端的適配工做已經有了突破性進展,正如Picasso在移動端取得的成就同樣,Picasso會在完成四端統一(Android、iOS、Web、小程序)的同時,構建出更快、更強的大前端實踐。
業界對大前端融合的將來有不少想象和憧憬,Picasso動態化實踐已經開啓大前端將來的一種新的可能。
Picasso暫時還未開源,如對Picasso有興趣,歡迎加入大衆點評的你們庭。
曉燕 Picasso核心SDK團隊負責人,八年移動應用開發經驗,2012年加入大衆點評。Picasso 核心SDK團隊致力於探索更好的客戶端動態化實踐方案,貢獻和維護高性能高可靠性的Picasso SDK,同時推動Picasso的應用和大生態的引導和建設。
大爲 Picasso項目負責人,點評平臺移動技術負責人,點評平臺在持續交付點評平臺性產品的同時,持續輸出支撐集團移動技術的框架和方案;點評平臺移動技術團隊同時也是廣義的Picasso團隊,全面參與建設了Picasso工具鏈,Picasso持續集成系統,Picasso分發系統,Picasso核心UI組件,點評平臺會持續助力集團移動端業務的動態化演進。