進階】之MultiDex的配置
隨著時代的進步,人們對手機 APP 的需求越來越大,越來越苛刻,很多APP都變得很大,再加上APP都不可避免的需要匯入一些框架、第三方類庫等等,就更加大了專案的整體檔案體系。如果檔案太多,系統可能會報如下錯誤:
UNEXPECTED TOP-LEVEL EXCEPTION: java.lang.IllegalArgumentException: method ID not in [0, 0xffff]: 65536 at com.android.dx.merge.DexMerger$6.updateIndex(DexMerger.java:501) at com.android.dx.merge.DexMerger$IdMerger.mergeSorted(DexMerger.java:282) at com.android.dx.merge.DexMerger.mergeMethodIds(DexMerger.java:490) at com.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:167) at com.android.dx.merge.DexMerger.merge(DexMerger.java:188) at com.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main.java:439) at com.android.dx.command.dexer.Main.runMonoDex(Main.java:287) at com.android.dx.command.dexer.Main.run(Main.java:230) at com.android.dx.command.dexer.Main.main(Main.java:199) at com.android.dx.command.Main.main(Main.java:103)
Android基於JAVA語言,JAVA語言在編譯之後都會生成位元組碼檔案.class,在Android中,這些檔案都被儲存在一個.dex檔案中。由於DEX檔案的格式限制,其中的Method、Field、Class的個數都不能超過short型別的最大值65535,如果超過了這個值,就會報上面的錯誤。
為了解決這個問題,Google - Android在API 21的時候為廣大程式設計師提供了一個通用的解決方案,就是今天要說的MultiDex方案。這個方案讓Android系統可以在原始的DEX檔案存滿之後自動生成一個新的DEX檔案,從而解決這個DEX溢滿的問題。
二、MultiDex的配置
MultiDex的配置主要是在Gradle檔案中進行的,但是不僅需要配置Module中的Gradle檔案,還需要配置專案根目錄下的Gradle檔案。
首先,我們先來配置Module中的Gradle檔案,檔案中的程式碼如下:
apply plugin: 'com.android.application' android { // productFlavors是為了避免每次執行都把DEX重新載入一遍而設定的兩套執行配置 productFlavors { dev { minSdkVersion 21 } prod { minSdkVersion 14 } } compileSdkVersion 24 buildToolsVersion "24.0.2" defaultConfig { applicationId "com.example.itgungnir.testmultidex" minSdkVersion 11 targetSdkVersion 24 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" // 設定MultiDex可用 multiDexEnabled true } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } // 保證其他的lib沒有被preDex dexOptions { preDexLibraries = false } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:24.2.1' testCompile 'junit:junit:4.12' // MultiDex的依賴 compile 'com.android.support:multidex:1.0.0' }
從程式碼中可以看到,這裡主要做了以下更改:
- 在android程式碼塊中加入了productFlavors和dexOptions兩個子程式碼塊;
- 添加了MultiDex的依賴包;
- 在defaultConfig程式碼塊中設定開啟了MultiDex。
配置完Module下的Gradle檔案,接下來配置Project下的Gradle檔案。檔案中的程式碼如下:
buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:2.2.0' } } allprojects { repositories { jcenter() } } task clean(type: Delete) { delete rootProject.buildDir } // 保證dex_files檔案中指定的檔案都載入到Main Dex中 afterEvaluate { tasks.matching { it.name.startsWith('dex') }.each { dx -> if (dx.additionalParameters == null) { dx.additionalParameters = [] } dx.additionalParameters += '--multi-dex' dx.additionalParameters += "--main-dex-list=$projectDir/dex_files".toString() } }
可以看到,這裡主要添加了afterEvaluate程式碼塊,最後一行中的dex_files是一個.txt檔案,其中存放著想要預設載入到MainDex中的所有檔案。這個dex_files檔案是和這個Gradle檔案在同一級目錄下,以下是dex_files.txt檔案中的程式碼(大家可以根據需要新增):
android/support/multidex/BuildConfig/class android/support/multidex/MultiDex$V14/class android/support/multidex/MultiDex$V19/class android/support/multidex/MultiDex$V4/class android/support/multidex/MultiDex/class android/support/multidex/MultiDexApplication/class android/support/multidex/MultiDexExtractor$1/class android/support/multidex/MultiDexExtractor/class android/support/multidex/ZipUtil$CentralDirectory/class android/support/multidex/ZipUtil/class
最後,需要在專案的Application檔案中注入MultiDex,程式碼如下:
public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); } @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); // 將MultiDex注入到專案中 MultiDex.install(this); } }
別忘了在Manifest檔案中註冊Application:
android:name=".MyApplication"
到此為止,MultiDex就已經配置好了,媽媽再也不用擔心我的專案dex溢位啦~~