隨著安卓平臺的不斷發(fā)展與壯大,市場上大而全的應用比比皆是,產(chǎn)品需求的變更累積和UI交互的極致追求,除了 resources 文件的俱增,在 Android Project 中依賴的 Library 和 自己寫的 Java 代碼也會越來越多。這些變化,除了會導致打包出的 APK 文件越來越大之外,當項目中java代碼包含的方法數(shù)(method count)超出一個峰值時。盡管在不同版本的編譯系統(tǒng)中顯示的錯誤內(nèi)容不盡相同,但都提到了一個具體的數(shù)字:65536,也就是本文要講到的核心內(nèi)容,Android 64K Method Counts Limit 的峰值。
Android 64K Method Counts Limit
Android Project 經(jīng)過編譯打包,其中的Java代碼(包括Library)轉(zhuǎn)化為DEX格式的字節(jié)碼文件,這是Android 5.0之前的Dalvik虛擬機決定的(5.0之后改為ART虛擬機),并且采用short類型引用DEX文件中的method,這也為method數(shù)量的峰值大小埋下了隱患。short類型能夠表示的最大值是65536,也就說單個DEX文件中最多只有65536個method能夠得到引用,如果代碼執(zhí)行了超出部分的method引用,自然會報錯,如methodNotFound等。1K等于1024,65536剛好是64K,為了便于稱呼和使用,就將這個限制統(tǒng)稱為64K方法數(shù)的引用限制。
為了解決64K方法數(shù)限制的問題,我們可以在項目中使用multidex配置,當項目中的方法數(shù)(包括:Android framework,library和我們自己寫的代碼)超過64K時,編譯系統(tǒng)會自動編譯出多個DEX文件。
Multidex Support
Android 5.0之前,安卓系統(tǒng)采用的是Dalvik虛擬機,采用的是JIT技術(shù)(Just-in-time compilation,即時編譯,運行時編譯DEX字節(jié)碼文件,這也是以前為什么安卓手機用戶總是詬病Android系統(tǒng)比iOS系統(tǒng)運行卡頓的原因),限制每個APK文件只能包含一個DEX文件(即classes.dex)。為了繞開這個限制,Google給我們提供了multidex support library兼容包,幫助我們實現(xiàn)應用程序加載多個DEX文件,并且這個兼容包作為程序的主DEX文件,管理者其他DEX文件的訪問。
Android 5.0之后,安卓系統(tǒng)改用了ART虛擬機(Android RunTime),采用的是OAT技術(shù)(Ahead-of-time,預編譯,在應用安裝的時候掃描應用中的所有DEX文件,并編譯成一個.oat格式的文件供安卓設(shè)備執(zhí)行,所以相比Dalvik虛擬機下的應用,安裝時間較長)。因此可以理解為,使用ART虛擬機下的安卓系統(tǒng)自動支持APK文件中多個DEX的加載。(注意:使用Instant Run時,如果項目中的minSdkVersion參數(shù)設(shè)為21或更高版本,Android Studio編譯運行時會自動使應用支持multidex。但Instant Run僅僅作用于debug版本,我們依然需要給release版本配置multidex來避開64K方法數(shù)的限制。)
Config for Multidex With Gradle
Android Gradle 插件在 Android SDK Build Tools 21.1 及更高版本的編譯工具上支持multidex作為編譯配置的一部分,所以確保我們的Android SDK Build Tools tools已經(jīng)更新至21.1或更高版本,然后再來配置應用的multidex部分。
第一步,修改app/build.grale文件,使項目能夠使用multidex:
第二步,修改AndroidManifest.xml文件,引用MultiDexApplication類,或者一般我們都是自定義繼承Application,此時就需要重寫attachBaseContext()方法,并在該方法里面調(diào)用MultiDex.install(this)來支持multidex。