前言
起因:項目使用的一直是multidex:1.0.3版本就想著版本低了要不要升級一下权烧。驚喜就這么來了颇玷。
65536
當(dāng)你的應(yīng)用及其引用的庫超過 65,536 個方法時,你會遇到構(gòu)建錯誤眠饮,表明你的應(yīng)用已達(dá)到 Android 構(gòu)建架構(gòu)的限制:
trouble writing output:
Too many field references: 131000; max is 65536.
You may try using --multi-dex option.
舊版本的構(gòu)建系統(tǒng)報告了不同的錯誤暑劝,這表明存在相同的問題:
Conversion to Dalvik format failed:
Unable to execute dex: method ID not in [0, 0xffff]: 65536
這兩種錯誤情況都顯示一個共同的數(shù)字:65536繁调。這個數(shù)字表示單個 Dalvik 可執(zhí)行文件 (DEX) 字節(jié)碼文件中的代碼可以調(diào)用的引用總數(shù)萨蚕。本問介紹了如何通過啟用稱為multidex的應(yīng)用程序配置來克服此限制,該配置允許你的應(yīng)用程序構(gòu)建和讀取多個 DEX 文件蹄胰。
關(guān)于 64K 參考限制
Android 應(yīng)用 APK 文件包含 Dalvik 可執(zhí)行文件 DEX 文件形式的可執(zhí)行字節(jié)碼文件岳遥,其中包含用于運行應(yīng)用的編譯代碼。Dalvik Executable 規(guī)范將單個 DEX 文件中可以引用的方法總數(shù)限制為 65,536裕寨,包括 Android 框架方法浩蓉、庫方法和你自己代碼中的方法。在計算機科學(xué)的上下文中宾袜,術(shù)語Kilo, K表示 1024(或 2^10)捻艳。由于 65,536 等于 64 X 1024,因此此限制稱為64K 參考限制庆猫。
解決64K限制
對 Android 5.0 及更高版本的 Multidex 支持
Android 5.0(API 級別 21)及更高版本使用稱為 ART 的運行時认轨,該運行時本機支持從 APK 文件加載多個 DEX 文件。 ART 在應(yīng)用安裝時執(zhí)行預(yù)編譯月培,它會掃描 classesN.dex 文件并將它們編譯成單個 .oat 文件以供 Android 設(shè)備執(zhí)行嘁字。 因此,如果你的 minSdkVersion 為 21 或更高杉畜,則默認(rèn)啟用 multidex纪蜒,并且你不需要 multidex 庫。
注意: 當(dāng)使用 Android Studio 運行你的應(yīng)用程序時此叠,構(gòu)建會針對你部署到的目標(biāo)設(shè)備進(jìn)行優(yōu)化纯续。 這包括在目標(biāo)設(shè)備運行 Android 5.0 及更高版本時啟用 multidex。 由于此優(yōu)化僅在使用 Android Studio 部署應(yīng)用程序時應(yīng)用拌蜘,因此你可能仍需要為 multidex 配置發(fā)布版本以避免 64K 限制杆烁。
看到?jīng)],這里最好的解決辦法就是設(shè)置minSdkVersion設(shè)置為 21 或更高简卧。這樣網(wǎng)上的一些什么
- multidex你遇到的坑
- multidex與你不得不說的秘密
- multidex原理及實現(xiàn)就和你沒得關(guān)系了兔魂,當(dāng)然你想了解也可以。
Android SDK 為 21 或更高的問題解決了举娩,那Android SDK 低于 21 的呢析校。咱接著往下看嘍构罗。
Android 5.0 之前的 Multidex 支持
為你的應(yīng)用程序配置 multidex
如果你的 minSdkVersion 設(shè)置為 21 或更高,則默認(rèn)啟用 multidex智玻,你不需要 multidex 庫遂唧。
但是,如果你的 minSdkVersion 設(shè)置為 20 或更低吊奢,那么你必須使用 multidex 庫并對你的應(yīng)用項目進(jìn)行以下修改:
1.修改模塊級 build.gradle 文件以啟用 multidex 并添加 multidex 庫作為依賴項盖彭,如下所示:
- 使用AndroidX
android {
defaultConfig {
...
minSdkVersion 15
targetSdkVersion 30
multiDexEnabled true
}
...
}
dependencies {
implementation "androidx.multidex:multidex:2.0.1"
}
- 不使用AndroidX(已棄用)
android {
defaultConfig {
...
minSdkVersion 15
targetSdkVersion 30
multiDexEnabled true
}
...
}
dependencies {
implementation 'com.android.support:multidex:1.0.3'
}
2.根據(jù)你是否覆蓋 Application 類,執(zhí)行以下操作之一:
- 如果你不覆蓋 Application 類页滚,請編輯你的清單文件以在 < application > 標(biāo)記中設(shè)置 android:name召边,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.scc.demo">
<application
android:name="androidx.multidex.MultiDexApplication" >
...
</application>
</manifest>
- 如果你確實覆蓋了 Application 類,請將其更改為擴展 MultiDexApplication(非必須)裹驰,如下所示:
public class MyApplication extends MultiDexApplication { ... }
- 或者隧熙,如果你確實覆蓋了 Application 類但無法更改基類,那么你可以覆蓋 attachBaseContext() 方法和 callMultiDex.install(this) 以啟用 multidex:
public class MyApp extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}
注意: 在 MultiDex.install() 完成之前幻林,不要通過反射或 JNI 執(zhí)行 MultiDex.install() 或任何其他代碼贞盯。 Multidex 跟蹤不會跟隨這些調(diào)用,導(dǎo)致 ClassNotFoundException 或由于 DEX 文件之間的類分區(qū)錯誤而導(dǎo)致驗證錯誤沪饺。
現(xiàn)在躏敢,當(dāng)你構(gòu)建應(yīng)用程序時,Android 構(gòu)建工具會根據(jù)需要構(gòu)建一個主要的 DEX 文件 (classes.dex) 和支持的 DEX 文件(classes2.dex整葡、classes3.dex 等)父丰。構(gòu)建系統(tǒng)然后將所有 DEX 文件打包到你的 APK 中。
在運行時掘宪,multidex API 使用特殊的類加載器來搜索所有可用的 DEX 文件以查找你的方法(而不是僅在主 classes.dex 文件中搜索)蛾扇。
multidex 庫的限制
multidex 庫有一些已知的限制,當(dāng)你將其合并到應(yīng)用程序構(gòu)建配置中時魏滚,你應(yīng)該注意并測試這些限制:
- 在啟動期間將 DEX 文件安裝到設(shè)備的數(shù)據(jù)分區(qū)上很復(fù)雜镀首,如果輔助 DEX 文件很大,可能會導(dǎo)致應(yīng)用程序無響應(yīng) (ANR) 錯誤鼠次。為避免此問題更哄,請啟用代碼收縮以最小化 DEX 文件的大小并刪除未使用的代碼部分。
- 在 Android 5.0(API 級別 21)之前的版本上運行時腥寇,使用 multidex 不足以解決 linearalloc 限制(問題 78035)成翩。此限制在 Android 4.0(API 級別 14)中有所增加,但這并沒有完全解決赦役。在低于 Android 4.0 的版本上麻敌,你可能會在達(dá)到 DEX 索引限制之前達(dá)到線性分配限制。因此掂摔,如果你的目標(biāo) API 級別低于 14术羔,請在平臺的這些版本上進(jìn)行徹底測試*宣谈,因為你的應(yīng)用程序可能在啟動時或加載特定類組時出現(xiàn)問題俱济。
代碼縮減可以減少或可能消除這些問題熔掺。
在主 DEX 文件中聲明所需的類
如果你收到 java.lang.NoClassDefFoundError捣郊,那么你必須通過在構(gòu)建類型中使用 multiDexKeepFile 或 multiDexKeepProguard 屬性聲明它們,根據(jù)主 DEX 文件中的要求手動指定這些附加類寥殖。 如果某個類在 multiDexKeepFile 或 multiDexKeepProguard 文件中匹配玩讳,則該類將添加到主 DEX 文件中。
multiDexKeepFile 屬性
你在multiDexKeepFile其中指定的文件應(yīng)每行包含一個類嚼贡,格式為com/example/MyClass.class. 例如锋边,你可以創(chuàng)建一個如下所示的文件multidex-config.txt:
com/scc/MyClass.class
com/scc/MyOtherClass.class
然后,你可以為構(gòu)建類型聲明該文件编曼,如下所示:
android {
buildTypes {
release {
multiDexKeepFile file('multidex-config.txt')
...
}
}
}
注意: Gradle 讀取相對于build.gradle文件的路徑,因此如果multidex-config.txt與build.gradle文件位于同一目錄中剩辟,則上述示例有效掐场。
multiDexKeepProguard 屬性
該multiDexKeepProguard文件使用與 Proguard 相同的格式,并支持整個 Proguard 語法贩猎。
你在multiDexKeepProguard其中指定的文件應(yīng)包含 -keep 任何有效 ProGuard 語法中的選項熊户。例如, -keep com.scc.MyClass.class吭服。你可以創(chuàng)建一個名為的文件 multidex-config.pro嚷堡,如下所示:
-keep class com.scc.MyClass
-keep class com.scc.MyClassToo
如果要指定包中的所有類,文件如下所示:
-keep class com.scc.** { *; } // com.scc 包中的所有類
然后艇棕,你可以為構(gòu)建類型聲明該文件蝌戒,如下所示:
android {
buildTypes {
release {
multiDexKeepProguard file('multidex-config.pro')
...
}
}
}
在開發(fā)版本中優(yōu)化 multidex
為了減少更長的增量構(gòu)建時間,使用 pre-dexing在構(gòu)建之間重用 multidex 輸出沼琉。Pre-dexing 依賴于僅在 Android 5.0(API 級別 21)及更高版本上可用的 ART 格式北苟。如果你使用的是 Android Studio 2.3 及更高版本,則在將你的應(yīng)用程序部署到運行 Android 5.0(API 級別 21)或更高版本的設(shè)備時打瘪,IDE 會自動使用此功能友鼻。
注意: 適用于 Gradle 3.0.0及更高版本的Android 插件包括進(jìn)一步改進(jìn)以優(yōu)化構(gòu)建速度,例如按類進(jìn)行 dexing(以便僅對你修改的類進(jìn)行重新索引)闺骚。一般來說彩扔,為了獲得最佳的開發(fā)體驗,你應(yīng)該始終升級到 最新版本的 Android Studio和 Android 插件僻爽。
但是虫碉,如果你從命令行運行 Gradle 構(gòu)建,則需要將 minSdkVersion 設(shè)置為 21 或更高以啟用 pre-dexing胸梆。保留生產(chǎn)版本設(shè)置的一個有用策略是使用產(chǎn)品風(fēng)格創(chuàng)建兩個版本的應(yīng)用程序 :開發(fā)風(fēng)格和發(fā)布風(fēng)格蔗衡,具有不同的值minSdkVersion纤虽,如下所示。
android {
defaultConfig {
...
multiDexEnabled true
//最低 API 級別绞惦。
minSdkVersion 15
}
productFlavors {
dev {
//(API 級別 21)或更高 .
minSdkVersion 21
}
prod {
// 如果你已經(jīng)為生產(chǎn)版本配置了 defaultConfig 塊
// 你的應(yīng)用程序逼纸,你可以將此塊留空,Gradle 會使用其中的配置
// 代替 defaultConfig 塊济蝉。 你仍然需要包括這種味道杰刽。
// 否則,所有變體都使用“dev”配置王滤。
}
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
}
dependencies {
implementation "androidx.multidex:multidex:2.0.1"
}
避免 64K 限制
在配置應(yīng)用以啟用 64K 或更多方法引用之前贺嫂,你應(yīng)該采取措施減少應(yīng)用代碼調(diào)用的引用總數(shù),包括應(yīng)用代碼定義的方法或包含的庫雁乡。以下策略可以幫助你避免達(dá)到 DEX 參考限制:
- 檢查你的應(yīng)用程序的直接和傳遞依賴項 - 確保你在應(yīng)用程序中包含的任何大型庫依賴項的使用方式都超過添加到應(yīng)用程序的代碼量第喳。一個常見的反模式是包含一個非常大的庫,因為一些實用方法是有用的踱稍。減少你的應(yīng)用程序代碼依賴性通城ィ可以幫助你避免 DEX 引用限制。
- 使用 R8 刪除未使用的代碼 -啟用代碼收縮以運行 R8 以用于你的發(fā)布版本珠月。啟用收縮可確保你不會隨 APK 一起發(fā)送未使用的代碼扩淀。
使用這些技術(shù)可能會幫助你避免在應(yīng)用中啟用 multidex,同時還可以減少 APK 的整體大小啤挎。
以上就是本文的全部內(nèi)容驻谆,希望對大家學(xué)習(xí)Android multidex有所幫助和啟發(fā)。