一、背景
隨著京東金融Android項目功能的不斷增加,代碼數(shù)量也隨之急劇增加钠四,雖然使用了MultiDex的處理,但是在不斷的加入更多類之后跪楞,我們依舊面臨著以下挑戰(zhàn):
問題1:編譯時出現(xiàn)錯誤com.Android.dex.DexException: Toomanyclasses in --main-dex-list, main dex capacity exceeded
產(chǎn)生原因:主dex超過最大方法數(shù)限制缀去。一個DEX文件中method個數(shù)采用使用原生類型short來索引文件中的方法,也就是4個字節(jié)共計最多表達65536個method甸祭,field/class的個數(shù)也均有此限制缕碎。
問題2:低端機上黑屏或白屏,冷啟動速度過慢
產(chǎn)生原因:dex加載耗時池户。在項目中使用Google提供的MultiDex后dex拆分為多個咏雌,而Android運行時只默認加載classes.dex這個文件(即主dex)。其他dex會在Application.attachBaseContext中使用Multidex.install進行解壓縮和加載校焦。Multidex.install是一個耗時大戶赊抖,會堵塞主線程,從而使主線程無法響應Activity的創(chuàng)建和初始化寨典。而5.0及以上版本已經(jīng)不存在這個問題氛雪,是由于ART模式的存在,app第一次安裝之后會進行一次預編譯(pre-compilation)耸成,如果這時候發(fā)現(xiàn)了classes(..N).dex文件就會將他們最終合成為一個.oat报亩,并在app啟動時一次性加載。
二墓猎、解決方案
面向問題1的解決方案:只要保證主dex中的方法數(shù)少于65536個捆昏,在gradle編譯腳本中加入dx.additionalParameters +='--set-max-idx-number=xxx'參數(shù)即可解決。
面向問題2的解決方案:首先想到的就是異步加載毙沾,但如果此時classloader需要加載某個類骗卜,而這個類卻沒有在主dex中,就會出現(xiàn)ClassNotfindException的異常崩潰,所以其實解決這兩個問題的根本方法是指定打包時將哪些類放到主dex中寇仓。
三举户、Scalpel介紹
Scalpel是京東金融客戶端研發(fā)的業(yè)界首個可以干預主dex生成的工具,可以根據(jù)配置文件指定某些符合規(guī)則的遍烦、及其必要的依賴類放到主dex中俭嘁。除了根據(jù)配置文件,Scalpel還會自動分析你的項目服猪,把一些必須放入主dex中的類找到并放進去供填。
在使用MultiDex時,BuildTool會自動把代碼拆成多個dex包罢猪,并通過掃描把Application , Activity , Service , ContentProvider和BrocastReceiver以及必要依賴類放進主dex包中近她,以下是Android的打包流程圖:
為了實現(xiàn)指定主dex中的類,我們在生成dex文件這一步時膳帕,使用gradle自定義Task來干預dex的生成過程,由于人工分析class有著不可維護性和高風險性粘捎,Scalpel則完美解決了對人工的依賴,從而極大的提高了生產(chǎn)效率危彩。
具體用法(寫法和混淆文件類似):
1.工程根目錄gradle.build中添加以下內容
repositories {
jcenter();
maven {
url "http://dl.bintray.com/gokuo/maven"
}
}
dependencies{
classpath 'com.jd.jrapp.plugin:Scalpel:1.0.1'
}
2:項目目錄下build.gradle中添加apply plugin: 'com.jd.jrapp.scalpel'
3:項目目錄下添加scalpel_rule.pro規(guī)則文件攒磨,并填寫以下內容
如:
(1)把supportv4包下所有的類和相關必要依賴類都打進主dex
-keep class android.support.v4.**{*;}
(2)把Fragment類打進主dex
-keep class android.support.v4.app.Fragment
(3)把Fragment類和相關必要依賴類打入主dex
-keep class android.support.v4.app.Fragment{*;}
(4)把所有Fragment的子類打入主dex
-keep class * extends android.support.v4.app.Fragment
四、實現(xiàn)原理
請參見源碼:https://github.com/gokuo/scalpel
五汤徽、提供支持
您如果有任何問題娩缰,可以在開源項目中提交bug報告,也可以發(fā)送郵件至 gaokuo@jd.com