作者:閑魚技術-景松
一、前沿
? 隨著閑魚的業務快速增長,運營類的需求也越來越多,其中不乏有很多界面修改或運營坑位的需求。閑魚的版本現在是每2週一個版本,如何快速迭代產品,跳過窗口期來滿足這些需求?另外,閑魚客戶端的包體也變的很大,企業包的大小,iOS已經到了94.3M,Android也到了53.5M。Android的包體大小,相比2016年,已經增長了近1倍,怎麼能將包體大小降下來?首先想到的是如何動態化的解決此類問題。
? 對於原生的能力的動態化,Android平臺各公司都有很完善的動態化方案,甚至Google還提供了Android App Bundles讓開發者們更好地支持動態化。由於Apple官方擔憂動態化的風險,因此並不太支持動態化。因此動態化能力就會考慮跟Web結合,從一開始基於 WebView 的 Hybrid 方案 PhoneGap、Titanium,到現在與原生相結合的 React Native 、Weex。
? 但Native和JavaScript Context之間的通訊,頻繁的交互就成了程序的性能瓶頸。於此同時隨著閑魚Flutter技術的推廣,已經有10多個頁面用Flutter實現,上面提到的幾種方式都不適合Flutter場景,如何解決這個問題Flutter的動態化的問題?
二、動態方案
我們最初調研了Google的動態化方案CodePush。
2.1 CodePush
? CodePush是谷歌官方推出的動態化方案,目前只有在Android上面實現了。Dart VM在執行的時候,載入isolate_snapshot_data
和isolate_snapshot_instr
2個文件,通過動態更改這些文件,就達到動態更新的目的。官方的Flutter源碼當中,已經有相關的提交來做動態更新的內容,具體內容可以參考 ResourceExtractor.java。
? 根據官方給出的Guide,我們這邊也做了相關的測試,patch的包體大小會很大(939kb)。為了降低包體大小,還可以通過增量的修改snapshot文件的方式來更新。通過bsdiff生成的snapshot的差異文件,2個文件分別可以縮小到48kb和870kb。
? 目前看來,CodePush還不能做到很好的工程化。而且如何管理patch文件,需要制定baseline和patch文件的規則。
2.2 動態模板
? 動態模板,就是通過定義一套DSL,在端側解析動態的創建View來實現動態化,比如LuaViewSDK、Tangram-iOS和Tangram-Android。這些方案都是創建的Native的View,如果想在Flutter裡面實現,需要創建Texture來橋接;Native端渲染完成之後,再將紋理貼在Flutter的容器裡面,實現成本很高,性能也有待商榷,不適合閑魚的場景。
? 所以我們提出了閑魚自己的Flutter動態化方案,前面已經有同事介紹過方案的原理:《做了2個多月的設計和編碼,我梳理了Flutter動態化的方案對比及最佳實現》,下面看下具體的實現細節。
三、模板編譯
自定義一套DSL,維護成本較高,怎麼能不自定義DSL來實現模板下發?閑魚的方案就是直接將Dart文件轉化成模板,這樣模板文件也可以快速沉澱到端側。
3.1 模板規範
? 先來看下一個完整的模板文件,以新版我的頁面為例,這個是一個列表結構,每個區塊都是一個獨立的Widget,現在我們期望將「賣在閑魚」這個區塊動態渲染,對這個區塊拆分之後,需要3個子控制項:頭部、菜單欄、提示欄;因為這3部分界面有些邏輯處理,所以先把他們的邏輯內置。