配置方法數(shù)超過 64K 的應用(轉(zhuǎn))

參考自:https://developer.android.google.cn/studio/build/multidex.html
我們在開發(fā)Androi應用的時候,有時會出現(xiàn)以下這種錯

//早期版本的構(gòu)建程序會出現(xiàn)這個錯
Conversion to Dalvik format failed:
Unable to execute dex: method ID not in [0, 0xffff]: 65536

//較新版本的 Android 構(gòu)建系統(tǒng)雖然顯示的錯誤不同十绑,但指示的是同一問題
trouble writing output:
Too many field references: 131000; max is 65536.
You may try using --multi-dex option.

這些錯誤都會顯示一個數(shù)字:65536。這個數(shù)子很重要,他代表的是單個Dalvik Executable(DEX)字節(jié)碼文件內(nèi)的代碼可調(diào)用的引用總數(shù)泻云。

關(guān)于64K引用限制

Android 應用 (APK) 文件包含 Dalvik Executable (DEX) 文件形式的可執(zhí)行字節(jié)碼文件,其中包含用來運行您的應用的已編譯代碼狐蜕。Dalvik Executable 規(guī)范將可在單個 DEX 文件內(nèi)可引用的方法總數(shù)限制在 65,536宠纯,其中包括 Android 框架方法、庫方法以及您自己代碼中的方法层释。在計算機科學領(lǐng)域內(nèi)婆瓜,術(shù)語千(簡稱 K)表示 1024(或 2^10)。由于 65,536 等于 64 X 1024,因此這一限制也稱為“64K 引用限制”廉白。

Android 5.0 之前版本的 Dalvik 可執(zhí)行文件分包支持

Android 5.0(API 級別 21)之前的平臺版本使用 Dalvik 運行時來執(zhí)行應用代碼个初。默認情況下,Dalvik 限制應用的每個 APK 只能使用單個 classes.dex 字節(jié)碼文件猴蹂。要想繞過這一限制院溺,您可以使用 Dalvik 可執(zhí)行文件分包支持庫,它會成為您的應用主要 DEX 文件的一部分磅轻,然后管理對其他 DEX 文件及其所包含代碼的訪問珍逸。

Android 5.0 及更高版本的 Dalvik 可執(zhí)行文件分包支持

Android 5.0(API 級別 21)及更高版本使用名為 ART 的運行時,后者原生支持從 APK 文件加載多個 DEX 文件聋溜。ART 在應用安裝時執(zhí)行預編譯谆膳,掃描 classesN.dex 文件,并將它們編譯成單個 .oat 文件撮躁,供 Android 設(shè)備執(zhí)行摹量。因此,如果您的 minSdkVersion 為 21 或更高值馒胆,則不需要 Dalvik 可執(zhí)行文件分包支持庫。
ART和Dalvik介紹

規(guī)避64K限制

在將您的應用配置為支持使用 64K 或更多方法引用之前凝果,您應該采取措施減少應用代碼調(diào)用的引用總數(shù)祝迂,包括由您的應用代碼或包含的庫定義的方法。下列策略可幫助您避免達到 DEX 引用限制:

  • 檢查您的應用的直接和傳遞依賴項 - 確保您在應用中使用任何龐大依賴庫所帶來的好處大于為應用添加大量代碼所帶來的弊端器净。一種常見的反面模式是型雳,僅僅為了使用幾個實用方法就在應用中加入非常龐大的庫。減少您的應用代碼依賴項往往能夠幫助您規(guī)避 dex 引用限制山害。
  • 通過 ProGuard 移除未使用的代碼 - 為您的版本構(gòu)建啟用代碼壓縮以運行 ProGuard纠俭。啟用壓縮可確保您交付的 APK 不含有未使用的代碼。

使用這些技巧使您不必在應用中啟用 Dalvik 可執(zhí)行文件分包浪慌,同時還會減小 APK 的總體大小冤荆。

配置您的應用進行 Dalvik 可執(zhí)行文件分包

如果你的 MinSdkVersion大于等于 21,只需要在模塊級build.gradle文件中將multiDexEnabled設(shè)置為true,
如下:

android {
    defaultConfig {
        ...
        minSdkVersion 21 
        targetSdkVersion 28
        multiDexEnabled true
    }
    ...
}

如果MinSdkVersion小于 21权纤,就比較麻煩了钓简。
須按如下方式使用 Dalvik 可執(zhí)行文件分包支持庫

  • 修改模塊級 build.gradle 文件以啟用 Dalvik 可執(zhí)行文件分包,并將 Dalvik 可執(zhí)行文件分包庫添加為依賴項汹想,如此處所示:
android {
    defaultConfig {
        ...
        minSdkVersion 15 
        targetSdkVersion 28
        multiDexEnabled true
    }
    ...
}

dependencies {
  compile 'com.android.support:multidex:1.0.3'
}
  • 根據(jù)是否要替換 Application 類外邓,執(zhí)行以下操作之一:

    • 如果您沒有替換 Application 類,請編輯清單文件古掏,按如下方式設(shè)置 <application> 標記中的 android:name

      <?xml version="1.0" encoding="utf-8"?>
      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.myapp">
          <application
                  android:name="android.support.multidex.MultiDexApplication" >
              ...
          </application>
        </manifest>
      
    • 如果您替換了 Application 類损话,請按如下方式對其進行更改以擴展 MultiDexApplication

      public class MyApplication extends MultiDexApplication { ... }
      
    • 或者,如果您替換了 Application 類,但無法更改基本類丧枪,則可以改為替換 attachBaseContext() 方法并調(diào)用 MultiDex.install(this) 來啟用 Dalvik 可執(zhí)行文件分包:

      public class MyApplication extends SomeOtherApplication {
            @Override
            protected void attachBaseContext(Context base) {
                 super.attachBaseContext(base);
                 MultiDex.install(this);
            }
      }
      

構(gòu)建應用后光涂,Android 構(gòu)建工具會根據(jù)需要構(gòu)建主 DEX 文件 (classes.dex) 和輔助 DEX 文件(classes2.dex 和 classes3.dex 等)。然后豪诲,構(gòu)建系統(tǒng)會將所有 DEX 文件打包到您的 APK 中顶捷。

運行時,Dalvik 可執(zhí)行文件分包 API 使用特殊的類加載器來搜索適用于您的方法的所有 DEX 文件(而不是僅在主 classes.dex 文件中搜索)屎篱。

Dalvik 可執(zhí)行文件分包支持庫的局限性

Dalvik 可執(zhí)行文件分包支持庫具有一些已知的局限性服赎,將其納入您的應用構(gòu)建配置之中時,您應該注意這些局限性并進行針對性的測試:

  • 啟動期間在設(shè)備數(shù)據(jù)分區(qū)中安裝 DEX 文件的過程相當復雜交播,如果輔助 DEX 文件較大重虑,可能會導致應用無響應 (ANR) 錯誤。在此情況下秦士,您應該通過 ProGuard 應用代碼壓縮以盡量減小 DEX 文件的大小缺厉,并移除未使用的那部分代碼。
  • 由于存在 Dalvik linearAlloc 錯誤(問題 22586)隧土,使用 Dalvik 可執(zhí)行文件分包的應用可能無法在運行的平臺版本早于 Android 4.0(API 級別 14)的設(shè)備上啟動提针。如果您的目標 API 級別低于 14,請務(wù)必針對這些版本的平臺進行測試曹傀,因為您的應用可能會在啟動時或加載特定類群時出現(xiàn)問題辐脖。代碼壓縮可以減少甚至有可能消除這些潛在問題。
  • 由于存在 Dalvik linearAlloc 限制(問題 78035)皆愉,因此嗜价,如果使用 Dalvik 可執(zhí)行文件分包配置的應用發(fā)出非常龐大的內(nèi)存分配請求,則可能會在運行期間發(fā)生崩潰幕庐。盡管 Android 4.0(API 級別 14)提高了分配限制久锥,但在 Android 5.0(API 級別 21)之前的 Android 版本上,應用仍有可能遭遇這一限制异剥。

聲明主 DEX 文件中需要的類

為 Dalvik 可執(zhí)行文件分包構(gòu)建每個 DEX 文件時瑟由,構(gòu)建工具會執(zhí)行復雜的決策制定來確定主要 DEX 文件中需要的類,以便應用能夠成功啟動冤寿。如果啟動期間需要的任何類未在主 DEX 文件中提供错妖,那么您的應用將崩潰并出現(xiàn)錯誤 java.lang.NoClassDefFoundError

該情況不應出現(xiàn)在直接從應用代碼訪問的代碼上疚沐,因為構(gòu)建工具能識別這些代碼路徑暂氯,但可能在代碼路徑可見性較低(如使用的庫具有復雜的依賴項)時出現(xiàn)。例如亮蛔,如果代碼使用自檢機制或從原生代碼調(diào)用 Java 方法痴施,那么這些類可能不會被識別為主 DEX 文件中的必需項。

因此,如果您收到 java.lang.NoClassDefFoundError辣吃,則必須使用構(gòu)建類型中的 multiDexKeepFilemultiDexKeepProguard 屬性聲明它們动遭,以手動將這些其他類指定為主 DEX 文件中的必需項。如果類在 multiDexKeepFilemultiDexKeepProguard 文件中匹配神得,則該類會添加至主 DEX 文件厘惦。

multiDexKeepFile 屬性

您在 multiDexKeepFile 中指定的文件應該每行包含一個類,并且采用 com/example/MyClass.class 的格式哩簿。例如宵蕉,您可以創(chuàng)建一個名為 multidex-config.txt 的文件,如下所示:

com/example/MyClass.class
com/example/MyOtherClass.class

然后节榜,您可以按以下方式針對構(gòu)建類型聲明該文件:

android {
    buildTypes {
        release {
            multiDexKeepFile file('multidex-config.txt')
            ...
        }
    }
}

請記住羡玛,Gradle 會讀取相對于 build.gradle 文件的路徑,因此如果 multidex-config.txt 與 build.gradle 文件在同一目錄中宗苍,以上示例將有效稼稿。

multiDexKeepProguard 屬性

multiDexKeepProguard 文件使用與 Proguard 相同的格式,并且支持整個 Proguard 語法讳窟。如需了解有關(guān) Proguard 格式和語法的詳細信息让歼,請參閱 Proguard 手冊中的 Keep Options 一節(jié)。

您在 multiDexKeepProguard 中指定的文件應該在任何有效的 ProGuard 語法中包含 -keep 選項丽啡。例如谋右,-keep com.example.MyClass.class。您可以創(chuàng)建一個名為 multidex-config.pro 的文件碌上,如下所示:

-keep class com.example.MyClass
-keep class com.example.MyClassToo

如果您想要指定包中的所有類,你可以使用-keep class com.example.** { *; }

然后浦徊,您可以按以下方式針對構(gòu)建類型聲明該文件:

android {
    buildTypes {
        release {
            multiDexKeepProguard('multidex-config.pro')
            ...
        }
    }
}

優(yōu)化開發(fā)構(gòu)建中的 Dalvik 可執(zhí)行文件分包

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末馏予,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子盔性,更是在濱河造成了極大的恐慌霞丧,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件冕香,死亡現(xiàn)場離奇詭異蛹尝,居然都是意外死亡,警方通過查閱死者的電腦和手機悉尾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門突那,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人构眯,你說我怎么就攤上這事愕难。” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵猫缭,是天一觀的道長葱弟。 經(jīng)常有香客問我,道長猜丹,這世上最難降的妖魔是什么芝加? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮射窒,結(jié)果婚禮上藏杖,老公的妹妹穿的比我還像新娘。我一直安慰自己轮洋,他們只是感情好制市,可當我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著弊予,像睡著了一般祥楣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上汉柒,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天误褪,我揣著相機與錄音,去河邊找鬼碾褂。 笑死兽间,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的正塌。 我是一名探鬼主播嘀略,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼乓诽!你這毒婦竟也來了帜羊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤鸠天,失蹤者是張志新(化名)和其女友劉穎讼育,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體稠集,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡奶段,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了剥纷。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片痹籍。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖晦鞋,靈堂內(nèi)的尸體忽然破棺而出词裤,到底是詐尸還是另有隱情刺洒,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布吼砂,位于F島的核電站逆航,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏渔肩。R本人自食惡果不足惜因俐,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望周偎。 院中可真熱鬧抹剩,春花似錦、人聲如沸蓉坎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛉艾。三九已至钳踊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間勿侯,已是汗流浹背拓瞪。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工义郑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留刹泄,地道東北人媚创。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓明棍,卻偏偏與公主長得像,于是被迫代替她去往敵國和親耐版。 傳聞我的和親對象是個殘疾皇子拱绑,可洞房花燭夜當晚...
    茶點故事閱讀 43,612評論 2 350

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