關(guān)于 64K 引用限制
隨著 Android 平臺(tái)的持續(xù)成長阱洪,Android 應(yīng)用的大小也在增加。當(dāng)您的應(yīng)用及其引用的庫達(dá)到特定大小時(shí)菠镇,您會(huì)遇到構(gòu)建錯(cuò)誤冗荸,指明您的應(yīng)用已達(dá)到 Android 應(yīng)用構(gòu)建架構(gòu)的極限。早期版本的構(gòu)建系統(tǒng)按如下方式報(bào)告這一錯(cuò)誤:
Conversion to Dalvik format failed:
Unable to execute dex: method ID not in [0, 0xffff]: 65536
較新版本的 Android 構(gòu)建系統(tǒng)雖然顯示的錯(cuò)誤不同利耍,但指示的是同一問題:
trouble writing output:
Too many field references: 131000; max is 65536.
You may try using --multi-dex option.
相信這個(gè)錯(cuò)誤大多是的Android開發(fā)者都遇到過蚌本,解決辦法也是比較簡單的盔粹,只要引入MultiDexApplication即可。
具體出現(xiàn)這個(gè)問題的原因是:
Android打包發(fā)布的時(shí)候會(huì)將所有的class都打包進(jìn)一個(gè)
.dex
文件中程癌。
Android 應(yīng)用 (APK) 文件包含 Dalvik Executable (DEX) 文件形式的可執(zhí)行字節(jié)碼文件舷嗡,其中包含用來運(yùn)行您的應(yīng)用的已編譯代碼。Dalvik Executable 規(guī)范將可在單個(gè) DEX 文件內(nèi)可引用的方法總數(shù)限制在 65,536嵌莉,其中包括 Android 框架方法进萄、庫方法以及您自己代碼中的方法。在計(jì)算機(jī)科學(xué)領(lǐng)域內(nèi)烦秩,術(shù)語千(簡稱 K)表示 1024(或 2^10)垮斯。由于 65,536 等于 64 X 1024,因此這一限制也稱為“64K 引用限制”只祠。
Android 5.0 之前版本的 Dalvik 可執(zhí)行文件分包支持
Android 5.0(API 級(jí)別 21)之前的平臺(tái)版本使用 Dalvik 運(yùn)行時(shí)來執(zhí)行應(yīng)用代碼兜蠕。默認(rèn)情況下,Dalvik 限制應(yīng)用的每個(gè) APK 只能使用單個(gè) classes.dex
字節(jié)碼文件抛寝。要想繞過這一限制熊杨,您可以使用 Dalvik 可執(zhí)行文件分包支持庫,它會(huì)成為您的應(yīng)用主要 DEX 文件的一部分盗舰,然后管理對(duì)其他 DEX 文件及其所包含代碼的訪問晶府。
Android 5.0 及更高版本的 Dalvik 可執(zhí)行文件分包支持
在5.0以上Android默認(rèn)支持
Android 5.0(API 級(jí)別 21)及更高版本使用名為 ART 的運(yùn)行時(shí),后者原生支持從 APK 文件加載多個(gè) DEX 文件钻趋。ART 在應(yīng)用安裝時(shí)執(zhí)行預(yù)編譯川陆,掃描 classesN.dex 文件,并將它們編譯成單個(gè) .oat 文件蛮位,供 Android 設(shè)備執(zhí)行较沪。因此,如果您的 minSdkVersion 為 21 或更高值失仁,則不需要 Dalvik 可執(zhí)行文件分包支持庫尸曼。
聲明主 DEX 文件中需要的類
為 Dalvik 可執(zhí)行文件分包構(gòu)建每個(gè) DEX 文件時(shí),構(gòu)建工具會(huì)執(zhí)行復(fù)雜的決策制定來確定主要 DEX 文件中需要的類萄焦,以便應(yīng)用能夠成功啟動(dòng)控轿。如果啟動(dòng)期間需要的任何類未在主 DEX 文件中提供,那么您的應(yīng)用將崩潰并出現(xiàn)錯(cuò)誤 java.lang.NoClassDefFoundError
拂封。
該情況不應(yīng)出現(xiàn)在直接從應(yīng)用代碼訪問的代碼上茬射,因?yàn)闃?gòu)建工具能識(shí)別這些代碼路徑,但可能在代碼路徑可見性較低(如使用的庫具有復(fù)雜的依賴項(xiàng))時(shí)出現(xiàn)烘苹。例如躲株,如果代碼使用自檢機(jī)制或從原生代碼調(diào)用 Java 方法,那么這些類可能不會(huì)被識(shí)別為主 DEX 文件中的必需項(xiàng)镣衡。
因此霜定,如果您收到 java.lang.NoClassDefFoundError
档悠,則必須使用構(gòu)建類型中的 multiDexKeepFile
或 multiDexKeepProguard
屬性聲明它們,以手動(dòng)將這些其他類指定為主 DEX 文件中的必需項(xiàng)望浩。如果類在 multiDexKeepFile
或 multiDexKeepProguard
文件中匹配辖所,則該類會(huì)添加至主 DEX 文件。
multiDexKeepFile 屬性
您在 multiDexKeepFile 中指定的文件應(yīng)該每行包含一個(gè)類磨德,并且采用 com/example/MyClass.class 的格式缘回。例如,您可以創(chuàng)建一個(gè)名為 multidex-config.txt 的文件典挑,如下所示:
com/example/MyClass.class
com/example/MyOtherClass.class
然后酥宴,您可以按以下方式針對(duì)構(gòu)建類型聲明該文件:
android {
buildTypes {
release {
multiDexKeepFile file 'multidex-config.txt'
...
}
}
}
multiDexKeepProguard 屬性
multiDexKeepProguard
文件使用與 Proguard 相同的格式,并且支持整個(gè) Proguard 語法您觉。如需了解有關(guān) Proguard 格式和語法的詳細(xì)信息拙寡,請(qǐng)參閱 Proguard 手冊(cè)中的 Keep Options 一節(jié)。
您在 multiDexKeepProguard
中指定的文件應(yīng)該在任何有效的 ProGuard 語法中包含 -keep
選項(xiàng)琳水。例如肆糕,-keep com.example.MyClass.class
。您可以創(chuàng)建一個(gè)名為 multidex-config.pro
的文件在孝,如下所示:
-keep class com.example.MyClass
-keep class com.example.MyClassToo
如果您想要指定包中的所有類诚啃,文件將如下所示:
-keep class com.example.** { *; } // All classes in the com.example package
然后,您可以按以下方式針對(duì)構(gòu)建類型聲明該文件:
android {
buildTypes {
release {
multiDexKeepProguard 'multidex-config.pro'
...
}
}
}