參考自:developer.android.google.cn/studio/buil… 咱們在開發Androi應用的時候,有時會出現如下這種錯html
//早期版本的構建程序會出現這個錯
Conversion to Dalvik format failed:
Unable to execute dex: method ID not in [0, 0xffff]: 65536
複製代碼
或java
//較新版本的 Android 構建系統雖然顯示的錯誤不一樣,但指示的是同一問題
trouble writing output:
Too many field references: 131000; max is 65536.
You may try using --multi-dex option.
複製代碼
這些錯誤都會顯示一個數字:65536。這個數子很重要,他表明的是單個Dalvik Executable(DEX)字節碼文件內的代碼可調用的引用總數。android
關於64K引用限制git
Android 應用 (APK) 文件包含 Dalvik Executable (DEX) 文件形式的可執行字節碼文件,其中包含用來運行您的應用的已編譯代碼。Dalvik Executable 規範將可在單個 DEX 文件內可引用的方法總數限制在 65,536,其中包括 Android 框架方法、庫方法以及您本身代碼中的方法。在計算機科學領域內,術語千(簡稱 K)表示 1024(或 2^10)。因爲 65,536 等於 64 X 1024,所以這一限制也稱爲「64K 引用限制」。github
Android 5.0(API 級別 21)以前的平臺版本使用 Dalvik 運行時來執行應用代碼。默認狀況下,Dalvik 限制應用的每一個 APK 只能使用單個 classes.dex
字節碼文件。要想繞過這一限制,您可使用 Dalvik 可執行文件分包支持庫,它會成爲您的應用主要 DEX 文件的一部分,而後管理對其餘 DEX 文件及其所包含代碼的訪問。bash
Android 5.0(API 級別 21)及更高版本使用名爲 ART 的運行時,後者原生支持從 APK 文件加載多個 DEX 文件。ART 在應用安裝時執行預編譯,掃描 classesN.dex 文件,並將它們編譯成單個 .oat 文件,供 Android 設備執行。所以,若是您的 minSdkVersion 爲 21 或更高值,則不須要 Dalvik 可執行文件分包支持庫。 ART和Dalvik介紹app
規避64K限制框架
在將您的應用配置爲支持使用 64K 或更多方法引用以前,您應該採起措施減小應用代碼調用的引用總數,包括由您的應用代碼或包含的庫定義的方法。下列策略可幫助您避免達到 DEX 引用限制:ide
使用這些技巧使您沒必要在應用中啓用 Dalvik 可執行文件分包,同時還會減少 APK 的整體大小。工具
配置您的應用進行 Dalvik 可執行文件分包
若是你的 MinSdkVersion
大於等於 21
,只須要在模塊級build.gradle
文件中將multiDexEnabled
設置爲true, 以下:
android {
defaultConfig {
...
minSdkVersion 21
targetSdkVersion 28
multiDexEnabled true
}
...
}
複製代碼
若是MinSdkVersion
小於 21
,就比較麻煩了。 須按以下方式使用 Dalvik 可執行文件分包支持庫:
build.gradle
文件以啓用 Dalvik 可執行文件分包,並將 Dalvik 可執行文件分包庫添加爲依賴項,如此處所示:android {
defaultConfig {
...
minSdkVersion 15
targetSdkVersion 28
multiDexEnabled true
}
...
}
dependencies {
compile 'com.android.support:multidex:1.0.3'
}
複製代碼
根據是否要替換 Application
類,執行如下操做之一:
若是您沒有替換 Application
類,請編輯清單文件,按以下方式設置 <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()
方法並調用 MultiDex.install(this)
來啓用 Dalvik 可執行文件分包:
public class MyApplication extends SomeOtherApplication {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}
複製代碼
構建應用後,Android 構建工具會根據須要構建主 DEX 文件 (classes.dex) 和輔助 DEX 文件(classes2.dex 和 classes3.dex 等)。而後,構建系統會將全部 DEX 文件打包到您的 APK 中。
運行時,Dalvik 可執行文件分包 API 使用特殊的類加載器來搜索適用於您的方法的全部 DEX 文件(而不是僅在主 classes.dex 文件中搜索)。
Dalvik 可執行文件分包支持庫的侷限性
Dalvik 可執行文件分包支持庫具備一些已知的侷限性,將其歸入您的應用構建配置之中時,您應該注意這些侷限性並進行鍼對性的測試:
聲明主 DEX 文件中須要的類
爲 Dalvik 可執行文件分包構建每一個 DEX 文件時,構建工具會執行復雜的決策制定來肯定主要 DEX 文件中須要的類,以便應用可以成功啓動。若是啓動期間須要的任何類未在主 DEX 文件中提供,那麼您的應用將崩潰並出現錯誤 java.lang.NoClassDefFoundError
。
該狀況不該出如今直接從應用代碼訪問的代碼上,由於構建工具能識別這些代碼路徑,但可能在代碼路徑可見性較低(如使用的庫具備複雜的依賴項)時出現。例如,若是代碼使用自檢機制或從原生代碼調用 Java 方法,那麼這些類可能不會被識別爲主 DEX 文件中的必需項。
所以,若是您收到 java.lang.NoClassDefFoundError
,則必須使用構建類型中的 multiDexKeepFile
或 multiDexKeepProguard
屬性聲明它們,以手動將這些其餘類指定爲主 DEX 文件中的必需項。若是類在 multiDexKeepFile
或 multiDexKeepProguard
文件中匹配,則該類會添加至主 DEX 文件。
您在 multiDexKeepFile 中指定的文件應該每行包含一個類,而且採用 com/example/MyClass.class 的格式。例如,您能夠建立一個名爲 multidex-config.txt 的文件,以下所示:
com/example/MyClass.class
com/example/MyOtherClass.class
複製代碼
而後,您能夠按如下方式針對構建類型聲明該文件:
android {
buildTypes {
release {
multiDexKeepFile file('multidex-config.txt')
...
}
}
}
複製代碼
請記住,Gradle 會讀取相對於 build.gradle 文件的路徑,所以若是 multidex-config.txt 與 build.gradle 文件在同一目錄中,以上示例將有效。
multiDexKeepProguard
文件使用與 Proguard 相同的格式,而且支持整個 Proguard 語法。如需瞭解有關 Proguard 格式和語法的詳細信息,請參閱 Proguard 手冊中的 Keep Options 一節。
您在 multiDexKeepProguard
中指定的文件應該在任何有效的 ProGuard 語法中包含 -keep
選項。例如,-keep com.example.MyClass.class
。您能夠建立一個名爲 multidex-config.pro
的文件,以下所示:
-keep class com.example.MyClass
-keep class com.example.MyClassToo
複製代碼
若是您想要指定包中的全部類,你可使用-keep class com.example.** { *; }
而後,您能夠按如下方式針對構建類型聲明該文件:
android {
buildTypes {
release {
multiDexKeepProguard('multidex-config.pro')
...
}
}
}
複製代碼