隨着業務擴張,代碼量越來越大,apk中單個dex方法數超過65K,就需要dex分包,Google官方推出了MultiDex來解決65K的問題,區分不同的Android虛擬機,會有一些問題。
Dalvik上,使用JIT(just in time),應用運行時,需要先將dex轉換成os上可以運行的機器碼,在此過程中,還會對dex文件進行優化(dexopt),因此在應用第一次啓動時,會經歷這些過程,apk解壓->dexopt->加載dex->字節碼轉換->啓動,在加載dex過程中,安裝第二個dex之後的dex涉及到io操作,在dex加載完成之前,應用需要一直等待,此過程耗時較長,如果dex文件過大,還會造成ANR;
ART上,使用oat(Ahead of time),在應用安裝時,dex就會被解壓優化完成,轉換成可執行的機器碼,之後應用在啓動時,只需要加載機器碼即可,所以不會出現啓動ANR的問題。
爲了解決Dalvik上冷啓動慢的問題,通常的方法是自定義第二個dex的加載流程,常用方案有以下幾種:
方案
原理
接入技術難度
優點
不足
風險
方案
原理
接入技術難度
優點
不足
風險
Google MultiDex
第一個啓動的進程的主線程上解壓安裝,同步執行,dex全部安裝完成之後,啓動應用
最簡單
dex加載完成之後,應用才真正開始運行,不會出現NoClassDefFoundError
啓動慢
dex文件過大時,在低配設備上可能會出現ANR、黑屏
微信/QQ
1、將dex文件放在assets文件夾下,加載前校驗md5(官方沒校驗);
2、四大組件的直接間接依賴都直接放在主dex中;
3、判斷是否已經dexopt,若已經dexopt,即放在attachBaseContext加載,反之放於地球中用線程加載(若判斷revision改變,即將dex以及dexopt目錄清空。只需簡單判斷兩個目錄dex名稱、數量是否與配置文件的一致)
最複雜,需要自己寫腳本掃描依賴集,以及自定義dex加載過程
啓動不會發生ANR,比Google的MultiDex更快
太過複雜,每次都需重新掃描依賴集,而且使用的是比較大的間接依賴集
無
1、使用自己開源的buck進行dex分包;
2、將加載Dex的邏輯放於單獨的nodex進程,這是一個非常簡單、輕量級的進程。它沒有任何的ContentProvider,只有有限的幾個Activity、Service;
3、將啓動LauncherActivity放在nodex進程,啓動時在nodex進程中安裝dex,主進程一直等待,dex安裝完成之後,啓動應用;
比Google的MultiDex稍複雜一些
依賴集非常簡單,同時首次加載Dex時也不會卡死
啓動主進程之前,必須先啓動nodex進程,額外增加了啓動時間(大約幾百毫秒)
無
美團
1、使用gradle插件進行分包,編譯期生成dex文件時,將入口Activity直接依賴的類放入主dex中;
2、多dex安裝時,先加載主dex,啓動應用,後續dex異步安裝,安裝完成之後,提供回調方法;
3、hook Activity的啓動過程,如果在異步加載dex期間就引用了未加載的類進行Activity跳轉,啓動一個Loading的頁面,直到所有dex加載完成;
接入很簡單,但是需要徹底解耦,否則主dex的方法數很容易超過65K,編譯不通過
啓動時間最快
有內部RD支持,方便定位問題
需要代碼高度解耦,要改動業務代碼
容易出現NoClassDefFoundError