Android 65536使用multidex

前言

起因:項目使用的一直是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)建類型中使用 multiDexKeepFilemultiDexKeepProguard 屬性聲明它們,根據(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ā)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末庆聘,一起剝皮案震驚了整個濱河市胜臊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌伙判,老刑警劉巖区端,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異澳腹,居然都是意外死亡织盼,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門酱塔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來沥邻,“玉大人,你說我怎么就攤上這事羊娃√迫” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長邮利。 經(jīng)常有香客問我弥雹,道長,這世上最難降的妖魔是什么延届? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任剪勿,我火速辦了婚禮,結(jié)果婚禮上方庭,老公的妹妹穿的比我還像新娘厕吉。我一直安慰自己,他們只是感情好械念,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布头朱。 她就那樣靜靜地躺著,像睡著了一般龄减。 火紅的嫁衣襯著肌膚如雪项钮。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天希停,我揣著相機與錄音烁巫,去河邊找鬼。 笑死脖苏,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的定踱。 我是一名探鬼主播棍潘,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼崖媚!你這毒婦竟也來了亦歉?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤畅哑,失蹤者是張志新(化名)和其女友劉穎肴楷,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體荠呐,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡赛蔫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了泥张。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呵恢。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖媚创,靈堂內(nèi)的尸體忽然破棺而出渗钉,到底是詐尸還是另有隱情,我是刑警寧澤钞钙,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布鳄橘,位于F島的核電站声离,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏瘫怜。R本人自食惡果不足惜术徊,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望宝磨。 院中可真熱鬧弧关,春花似錦、人聲如沸唤锉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽窿祥。三九已至株憾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間晒衩,已是汗流浹背嗤瞎。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留听系,地道東北人贝奇。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像靠胜,于是被迫代替她去往敵國和親掉瞳。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容