本文翻譯自http://developer.android.com/intl/zh-cn/tools/building/multidex.html#about。主要介紹當我們Android App中函數超過65536時構建失敗的原因及解決辦法! ------------------------...
本文翻譯自http://developer.android.com/intl/zh-cn/tools/building/multidex.html#about。主要介紹當我們Android App中函數超過65536時構建失敗的原因及解決辦法!
-------------------------分割線--------------------------------------------------
隨著android platform的持續增長,android apps的大小也在增長。當你的應用程式包括其所引用的庫達到一定的規模,你將遇到構建錯誤,這表明你的程式已經達到到了android 應用框架的限制。在早期的構建系統會報告如下錯誤信息:
Conversion to Dalvik format failed:
Unable to execute dex: method ID not in [0, 0xffff]: 65536
最近版本的構建系統會顯示不同的錯誤,這是同一個問題的提示信息:
trouble writing output: Too many field references: 131000; max is 65536. You may try using --multi-dex option.
這兩種錯誤情況顯示了一個共同的數字:65536。這個數字代表的是單個Dalvik可執行的(DEX)位元組碼文件的可以調用方法總數。如果你已經創建了android應用,並且收到了這個錯誤,那麼恭喜你,你的代碼太多了!本文檔將介紹如何突破這個限制,繼續構建你的app。
About the 65K Reference Limit
APK文件包含用於運行你的應用程式編譯代碼形式的可執行位元組碼文件(Dalvik Executable DEX)。Dalvik可執行的規範限制了在一個單一的DEX文件中引用到包括Android框架方法,庫方法等方法的總數為65,536。想要突破此限制,您需要配置您的應用程式的構建過程,生成多個DEX文件,被稱為multidex配置。
Multidex support prior to Android 5.0
Android5.0之前的版本使用的Dalvik運行時執行應用程式代碼。預設情況下,Dalvik的限制的應用程式,每APK一個classes.dex位元組碼文件。為瞭解決這個限制,可以使用multidex support library,成為您的應用程式的主DEX文件的一部分,然後設法獲得了額外的DEX文件和它們所包含的代碼。
Multidex support for Android 5.0 and higher
Android5.0以及更高版本使用的是ART runtime,可以支持原生從APK文件中載入多個dex文件。ART進行預編譯的應用程式安裝時它會掃描類(.. N).dex文件,並通過Android設備編譯成一個單一的.oat文件執行。對於在Android5.0運行時的詳細信息,請參考 Introducing ART。
Avoiding the 65K Limit
在配置您的應用程式能夠使用65K+方法個數之前,您應該採取措施來減少您的應用程式代碼調用引用的總數,包括您的應用程式代碼中的方法和庫定義的方法。以下策略可以幫助您避免超過DEX參考限值:
看您的應用程式的直接和間接性依賴:確保在你的app中包含的library的用途要和其代碼量匹配。一個比較常見的反例就是包含巨大的代碼量,用途卻很小。減少你的app的library依賴往往可以幫你避免dex reference限制。
刪除未使用的代碼混淆(code with ProGuard):配置可以運行你的app的ProGuard並確保可以在正式構建程式的時候為你的程式瘦身。
使用這些技術可以幫助你避免更改程式構建配置時需要啟用更多的方法引用。對於寬頻成本很高的市場來說,這些步驟很重要。
Configuring Your App for Multidex with Gradle
Android插件Gradle 可Android SDK Build Tools 21.1和更高版本中支持multidex作為構建配置的一部分。在為你app配置multidex之前,請先使用SDK Manager將Android SDKBuild Tools 和Android Support Repository更新到最新版本。
在你的app中使用multidex配置之前,需要對你的程式開發做一些相應修改。你需要執行以下步驟:
1.修改你的 Gradle構建配置以啟用multidex
2.修改你的AndroidManifest 去引用MultiDexApplication class。
修改build.gradle配置去引用support library和啟用multidex輸出,如以下所示build.gradle片段
android { compileSdkVersion 21 buildToolsVersion "21.1.0" defaultConfig { ... minSdkVersion 14 targetSdkVersion 21 ... // Enabling multidex support. multiDexEnabled true } ... } dependencies { compile 'com.android.support:multidex:1.0.0' }
Note:你可以在build.gradle文件的defaultConfig,buildType,或者productFlavor中設置multiDexEnable。
在你的AndroidManifest的application元素中添加MultiDexApplication class:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.android.multidex.myapplication"> <application ... android:name="android.support.multidex.MultiDexApplication"> ... </application> </manifest>
當這些配置添加到一個應用程式中,Android構建工具會構建一個dex(classes.dex),根據需要會繼續構建(classes2.dex, classes3.dex)。然後構建系統將他們打包進同一個apk中。
Note: 如果你的app使用了自己定義的Application class,你可以重寫attachBaseContext()方法併在其中調用MultiDex.install(this)去實現multidex。更多信息請參考MultiDexApplication
Limitations of the multidex support library
你應該意識到multidex support library有一些已知的限制,所以當你在將他合併到你的應用程式中時需要測試一下:
1..dex文件的安裝在啟動設備的數據分區很複雜,如果二級dex文件太大可能導致程式沒有響應(ANR)。在這種情況下,您應與混淆器(ProGuard)應用代碼縮減技術,減少.dex文件的大小和刪除未使用的部分代碼。
2.程式不能在在早已Android4.0(API level 14)之前的版本上使用multidex由於a Dalvik linearAlloc bug(Issue 22586)(http://b.android.com/22586)如果你使用API Level 14之前的版本,確保執行您的應用程式在啟動時或者裝載特定的類時,測試你的程式是否會出現問題。代碼縮減可以消除這些潛在問題。
3.應用程式使用multidex配置會發出非常大的記憶體分配請求,這可能會導致運行時崩潰,由於a Dalvik linearAlloc bug(Issue 78035)(http://b.android.com/78035)。
4.Dalvik runtime執行時the primary dex文件可能需要複雜的請求。Android build tooling 更新處理Android需求,但是其他included libraries可能有額外的依賴需要,包括調用本地的java代碼。一些library可能無法使用,直到multidex build tools更新後允許您指定必須包含在主dex文件的類。
Optimizing Multidex Development Builds
multidex配置需要顯著增加構建處理時間,因為構建系統必須做出複雜決定,來確定哪些類必須包含在主dex文件以及哪些類可以包含在第二級dex文件中。這意味著常規構建執行與multidex作為開發過程的一部分,通常需要更長的時間,這可能減緩你的程式開發進度。
為了減少multidex輸出構建時間,你應該創建兩個變數來使用Android構建輸出插件Gradle productFlavors: a development flavor and a production flavor。
a development flavor,設定一個最低21的SDK版本。這個設置生成multidex輸出比使用ART-supported格式要快得多。the release flavor,設定一個最低SDK版本匹配你的項目最低支持版本。這個設置生成一個multidex APK,與更多的設備相容,但需要更長的時間來構建。
以下構建配置示例演示瞭如何在Gradle構建文件設置這些 flavors :
android {
productFlavors {
// Define separate dev and prod product flavors.
dev {
// dev utilizes minSDKVersion = 21 to allow the Android gradle plugin
// to pre-dex each module and produce an APK that can be tested on
// Android Lollipop without time consuming dex merging processes.
minSdkVersion 21
}
prod {
// The actual minSdkVersion for the application.
minSdkVersion 14
}
}
...
buildTypes {
release {
runProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
}
dependencies {
compile 'com.android.support:multidex:1.0.0'
}
View Code
完成了這個配置更改後,您可以使用與app的devDebug變數相結合的屬性dev productFlavor和debug buildType。利用這個去創建一個minSdkVersion為Android API Level 21不使用proguard,啟用multidex的debug app 。這些設置使Android gradle插件執行以下操作:
1.構建應用程式的每個模塊(包括依賴庫)作為單獨的dex文件。這通常被稱為pre-dexing。
2.包括每個dex文件沒有修改APK文件
3.最重要的是,dex的模塊文件不會被結合,所以可以避免來確定主dex文件內容的長時間運行的計算。
這些設置導致快速、增量構建,因為只有dex文件修改模塊的會重新計算,重新包裝成APK文件。這些設置構建APK只能用於測試Android 5.0及以上設備。然而,通過實現配置的flavors,你能夠執行正常構建release-appropriate最低SDK和proguard設置
還可以建立其他變數,包括構建prodDebug變數,這需要更長的時間來構建,但可以用於測試外的開發。如果你從命令行執行gradle任務,您可以使用標準命令在結束的位置附加DevDebug(如./ gradlew installDevDebug)。
關於使用flavors與Gradle任務的更多信息,參考Gradle Plugin User Guide(http://tools.android.com/tech-docs/new-build-system/user-guide)
Tip:您也可以提供一個自定義清單,或者為每個flavor自定義一個應用程式類,允許你在變數需要的時候使用MultiDexApplication應用程式類庫或者調用 MultiDex.install()。
Using Build Variants in Android Studio
Build variants對管理multidex構建過程是非常有用的,Android Studio可以使用可視化操作來選擇這些變數。
1.打開位於 left-sidebar的Build Variants 視窗(一般是在Android studio的左下)
2.點擊Build Variants的名稱來選擇不同的變數,,如圖1所示
Testing Multidex Apps
當multidex應用程式中使用instrumentation tests時,需要進行額外的配置。因為代碼在multidex應用程式中不是位於單一DEX文件。所以instrumentation tests不能正常運行,除非程式為multidex配置。
為了使用instrumentation tests測試multidex app,需要配置MultiDexTestRunner。
下麵build.gradle文件演示瞭如何配置來使用這個測試運行器:
android {
defaultConfig {
...
testInstrumentationRunner "com.android.test.runner.MultiDexTestRunner"
}
}
Note: With Android Plugin for Gradle versions lower than 1.1, you need to add the following dependency for multidex-instrumentation:
dependencies {
androidTestCompile('com.android.support:multidex-instrumentation:1.0.1') {
exclude group: 'com.android.support', module: 'multidex'
}
}
你可以用instrumentation tests runner class直接或擴展它來適應您的測試需求。或者,您可以在現有的instrumentation中覆蓋onCreate:
public void onCreate(Bundle arguments) {
MultiDex.install(getTargetContext());
super.onCreate(arguments);
...
}
Note: Use of multidex for creating a test APK is not currently supported.