Android Studio利用android-support-multidex解決65536問題(64k問題)

64k的各種異常

當你的應用程序和庫引用達到一定規模,你遇到構建錯誤顯示你的應用已經達到了一個Android應用程序構建體系結構的限制。早期版本的構建系統報告這個錯誤如下:

Conversion to Dalvik format failed:
Unable to execute dex: method ID not in [0, 0xffff]: 65536
或者

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構建系統顯示一個不同的錯誤,但是是同樣一個問題:

trouble writing output:
Too many field references: 131000; max is 65536.
You may try using --multi-dex option.

或者(我遇到的就是這種)

Error:The number of method references in a .dex file cannot exceed 64K.

上面的錯誤顯示一個共同的數字:65536。這個數字是重要的,它代表了引用的總數,可以在單個調用的代碼Dalvik可執行(Dex)字節碼文件。如果你的Android應用發生這個錯誤,恭喜你,你的代碼已經達到了一定的量!本文解釋瞭如何解決這個限制並繼續構建應用程序。

關於64 k引用限制

Android應用程序(APK)在Dalvik可執行文件的形式包含可執行的字節碼文件(DEX)文件,其中包含已編譯的代碼來運行你的應用程序。Dalvik可執行規格限制一個Dex文件包含65536個方法:包括Android框架方法、Library方法的總數、和你自己的代碼方法總數。因爲65536等於64×1024,這一限制被稱爲“64k引用限制”。 
這個極限就要求我們配置應用程序的構建過程,需要生成多個DEX文件,所以稱爲multidex 配置。

分析原因與注意事項

解決方法分Android 5.0及以上系統和5.0以下系統怎麼做。客官們不要着急,先看我一個個分析原因,畢竟我要裝下逼哈哈。

一、Android 5.0以下的版本

Android 5.0(API leve 21)之前的系統使用Dalvik執行應用程序代碼。默認情況下,Dalvik限制一個apk只有一個Dex文件。爲了繞過這個限制, 我們可以使用multidex support library,它成爲我們APK的主要DEX文件的一部分,負責管理我們APK訪問其他DEX文件和代碼。

注意: 如果咱的項目minSdkVersion是20或更低,運行到Android 4.4(API leve 20)或者更低版本的設備上時需要禁用AndroidStudio的即時運行

二、Android 5.0和更高版本

Android 5.0(API leve 21)和更高的系統使用runtime是ART ,原生支持從應用的apk文件加載多個DEX文件。ART在安裝應用時預編譯應用程序,會掃描多個classes(..N).dex文件編譯成一個.oat的文件。更多Android5.0 runtime的更多信息,請參見即時運行-instant-run

注意: 如果你使用即時運行 , AndroidStudio自動配置你的應用程序,你應用程序的minSdkVersion應該設置爲21或更高。因爲即時只工作在你APP的Debug版本,你任然需要配置你的release版本構建時用multidex避免64k的限制。

儘量避免64k限制

在配置我們的App啓用64k或者更多方法引用之前,我們可以減少應用代碼內的調度總數,包括我們自身應用的方法和第三方的庫,下面的幾個策略或許可以幫到你:

  • 檢查你的APP的直接和間接的過度依賴關係:有時候我們用到某個Libaray的某幾個方法或者功能時這個庫非常大,減少這種依賴可能對與避免64k的問題非常有效。
  • 在正式打包構建的時候,使用代碼混淆器ProGuard混淆移除未使用的代碼,也就是不把沒有使用的代碼打包到我們的apk中。

使用上面的方法可以幫助我們避免在應用程序中生成太多無用的方法和減小我們apk的大小,這對於用自己服務器做app更新升級的同學是非常有幫助的。

這裏給大家推薦下任玉剛同學的插件式開發框架:https://github.com/singwhatiwanna/dynamic-load-apk,共同參與開發者:田嘯,宋思宇。

解決64k問題

Android SDK Build Tools 21.1或者更高版本的build工具中用Android plugin gradle。確保你更新Android SDK build toolsAndroid support到最新版本,然後用multidex配置應用程序。我們必須要做兩步。

第一步,修改主module的build.gradle文件

在gradle中依賴multidex,並啓用multiDexEnable

android {
    compileSdkVersion 21
    buildToolsVersion 

    defaultConfig {
        ...
        minSdkVersion 14
        targetSdkVersion 21
        ...

        // Enabling multidex support.
        multiDexEnabled true
    }
    ...
}

dependencies {
  compile 'com.android.support:multidex:1.0.1'
}

第二步,繼承android.support.multidex.MultiDexApplication

兩種情況

第一種情況,如果我們的APP沒有重寫過Application類,我們直接繼承MultiDexApplication,然後在manifest.xml中註冊Application即可。

第二種情況,如果我們已經重寫過Application類,重寫attachBaseContext(Context)方法,並調用MultiDex.install(this);即可:

protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);

因爲我翻過MultiDexApplication的源碼了,裏面就是重寫了這個方法而已哈哈:

public class MultiDexApplication extends Application {
    public MultiDexApplication() {
    }

    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);
    }
}

註冊Application

<?xml version= encoding=?>
<manifest xmlns:android=
    package=>
    <application
        ...
        android:name="剛纔重寫的Application全類名">
        ...
    </application>
</manifest>

multidex庫的一些限制因素

  • DEX文件安裝到設備的過程非常複雜,如果第二個DEX文件太大,可能導致應用無響應。此時應該使用ProGuard減小DEX文件的大小。
  • 由於Dalvik linearAlloc的Bug,應用可能無法在Android 4.0之前的版本啓動,如果你的應用要支持這些版本就要多執行測試。
  • 同樣因爲Dalvik linearAlloc的限制,如果請求大量內存可能導致崩潰。Dalvik linearAlloc是一個固定大小的緩衝區。在應用的安裝過程中,系統會運行一個名爲dexopt的程序爲該應用在當前機型中運行做準備。dexopt使用LinearAlloc來存儲應用的方法信息。Android 2.2和2.3的緩衝區只有5MB,Android 4.x提高到了8MB或16MB。當方法數量過多導致超出緩衝區大小時,會造成dexopt崩潰。
  • Multidex構建工具還不支持指定哪些類必須包含在首個DEX文件中,因此可能會導致某些類庫(例如某個類庫需要從原生代碼訪問Java代碼)無法使用。

使用了multidex後的構建優化

一、因此如果應用中包含lirary工程,可能會發生如下錯誤:

UNEXPECTED TOP-LEVEL EXCEPTION:  
com.android.dex.DexException: Library dex files are not supported in multi-dex mode 

這個時候我們需要禁用預編譯:

android {  
    ...  
    dexOptions {  
        preDexLibraries = false  
    }  
    ...
}  

二、如果在運行的時候遇到如下錯誤:

UNEXPECTED TOP-LEVEL ERROR:  
java.lang.OutOfMemoryError: Java heap space 

我們需要加大java堆內存大小:

maxProcessCount 4 // this is the default value
javaMaxHeapSize "2g"

三、提升運行速度 
在Android leve 21或者更高SDK版本。使用ART-supported格式生成multidex輸出更快,爲我們節省時間,所以我們不必在調試的使用也兼容到5.0以下,所以我們配置最低版本的時候做個如下兼容:

android {
    productFlavors {
        // 自定義偏好設置.
        dev {
            // 在Android leve 21或更高版本編譯更快
            minSdkVersion 21
        }
        prod {
            // 真正的生產環境.
            minSdkVersion 14
        }
    }
    ...
}
dependencies {
  compile 'com.android.support:multidex:1.0.1'
}

Android plugin Gradle版本低於1.1怎麼辦

你需要添加 以下依賴 multidex-instrumentation :

dependencies {
    androidTestCompile('com.android.support:multidex-instrumentation:1.0.1') {
         exclude group: 'com.android.support', module: 'multidex'
    }
}

Eclipse Jar包下載:http://download.csdn.net/detail/yanzhenjie1003/9566518 
官方參考文檔:https://developer.android.com/tools/building/multidex.html

以上內容轉自嚴振杰的博客: http://blog.csdn.net/yanzhenjie1003


你以爲這樣就完了,並沒有!
如果在打包或者編譯時出現OOM的情況,可參照下面這篇文章,修改gradle-properties

http://blog.csdn.net/oshenli1/article/details/52622009
發佈了60 篇原創文章 · 獲贊 18 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章