Android分包MultiDex原理詳解

來源:互聯網
上載者:User

標籤:

MultiDex的產生背景

當Android系統安裝一個應用的時候,有一步是對Dex進行最佳化,這個過程有一個專門的工具來處理,叫DexOpt。DexOpt的執行過程是在第一次載入Dex檔案的時候執行的。這個過程會產生一個ODEX檔案,即Optimised Dex。執行ODex的效率會比直接執行Dex檔案的效率要高很多。

但是在早期的Android系統中,DexOpt有一個問題,DexOpt會把每一個類的方法id檢索起來,存在一個鏈表結構裡面。但是這個鏈表的長度是用一個short類型來儲存的,導致了方法id的數目不能夠超過65536個。當一個項目足夠大的時候,顯然這個方法數的上限是不夠的。儘管在新版本的Android系統中,DexOpt修複了這個問題,但是我們仍然需要對低版本的Android系統做相容。

為瞭解決方法數超限的問題,需要將該dex檔案拆成兩個或多個,為此Google官方推出了multidex相容包,配合AndroidStudio實現了一個APK包含多個dex的功能。

MultiDex的簡要原理

我們以APK中有兩個dex檔案為例,第二個dex檔案為classes2.dex。

  1. 相容包在Applicaion執行個體化之後,會檢查系統版本是否支援 multidex,classes2.dex是否需要安裝。
  2. 如果需要安裝則會從APK中解壓出classes2.dex並將其拷貝到應用的沙箱目錄下。
  3. 通過反射將classes2.dex注入到當前的classloader中。

下面引入一下官方的文檔。

https://developer.android.com/tools/building

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

當然,也有一些系統裝置會出現以下log資訊,不過反饋的是同一個問題:

/multidex.html#about 
筆者,針對官方文檔的翻譯如下:

構建超過65K方法的App

隨著Android裝置的慢慢發展,App的大小會變得越來越大。當我們在開發App的時候由於報的大小和引用庫的原因,我們在編譯我們項目的時候通常會遇到下面一個錯誤:

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

這兩個錯誤條件顯示一個共同的數字:65536。這個數字,它表示的是你在一個dex包中的函數方法超過了65535個。

如果你已經構建了一個Android App時,並收到了這個錯誤,那麼恭喜你,你有很多代碼!

下面我們就具體說說,如何解決這個問題。

 

關於65K方法限制

我們知道Android中的可執行偉劍都儲存在dex檔案中,其中包含已編譯的代碼來運行你的應用程式。Dalvik虛擬機器對可執行dex檔案的規格是有方法限制的,即一個單一的dex檔案的方法總數最多為65536。

其中包括:

  • 引用的Android Framework方法
  • library的方法
  • 我們自己書寫代碼的方法。

為了突破這個方法數的限制,我們就提出了一個方案——產生多個dex檔案。這個多個dex檔案的方案,我們又稱為multidex方案配置。

Multidex支援Android 5.0之前的版本 
    Android5.0版本的平台之前,Android使用的是Dalvik Runtime執行的程式碼。預設情況下,限制應用到一個單一的classes.dex。

Dalvik位元組碼檔案每APK。為了繞過這個限制,你可以使用multidex支援庫,成為你的應用程式的主要部分和DEX檔案進行管理,獲得額外的dex檔案,它們包含的代碼。

Multidex支援Android 5.0及更高版本 
    Android 5.0和更高的Runtime 如art,本身就支援從應用的APK檔案載入多個DEX檔案。art支援先行編譯的應用程式在安裝時掃描類(..)。Dex檔案編譯成一個單一的Android裝置上執行.oat檔案。

避免65K限制

當你確定使用multidex的分包策略的時候,請你先確定自己的代碼中都是優秀的。你還需要做以下幾步:

  • 去掉一些未使用的import和library
  • 使用ProGuard去掉一些未使用的代碼
用Gradle配置使用Multidex

Android 的 Gradle外掛程式在 Android Build Tool 21.1開始就支援使用multidex了。

設定你的應用程式開發項目中使用multidex配置,要求你做出一些修改您的應用程式開發項目。:

  • 修改Gradle的配置,支援multidex
  • 修改你的manifest。讓其支援multidexapplication類

修改Gradle的build如下:

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‘}

Tips: 你可以在Gradle設定檔中的 multiDexEnabled 在 defaultConfig、 
buildType、productFlavor選項設定。

在manifest檔案中,添加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>

當然,如果你重寫了 Application,就對自訂Application的繼承方式做一個修改。

 

Multidex的方式的局限性

雖然我們開起來multidex是一個極好的東西,但是multidex還是存在自己的局限性,我們在開發測試之前要清楚局限性是什麼:

  1. 如果二DEX檔案太大,安裝分割dex檔案是一個複雜的過程,可能會導致應用程式無響應(ANR)的錯誤。在這種情況下,你應該盡量的減小dex檔案的大小和刪除無用的邏輯,而不是完全依賴於multidex。
  2. 在Android 4.0裝置(API Level 14)之前,由於Dalvik linearalloc bug(問題22586),multidex很可能是無法啟動並執行。如果希望運行在Level 14之前的Android系統版本,請先確保完整的測試和使用。
  3. 應用程式使用了multiedex配置的,會造成使用比較大的記憶體。當然,可能還會引起dalvik虛擬機器的崩潰(issue 78035)。
  4. 對於應用程式比較複雜的,存在較多的library的項目。multidex可能會造成不同依賴項目間的dex檔案函數相互調用,找不到方法。
最佳化multidex開發和構建

一個multidex的配置,對系統apk的構建、簽名、打包複雜性大大的增加。這就意味著,你每一次的構建過程都是相當耗時的。

為了加快我們的開發速度,加快構建的過程,我們可以在Gradle productFlavors建立出來一個 development flavor 和 production flavor 來滿足我們不同構建需求。

下面是一個列子示範我們如何設定這些flavors在Gradle build檔案中:

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‘}

在你完成了傷處的配置修改之後,你配置productFlavor 和 buildType來使用 ,devDebug 變種app。使用這些變種app,可以設定proguard disable、multidex enable方便我們測試。

這些配置需要針對Android Gradle外掛程式做如下操作:

  1. 在分包前,編譯應用程式中的每一個module包括依賴項目,這個步驟稱為 pre-dexing。
  2. include每一個dex檔案
  3. 最重要的是,對於主dex檔案,不會做切分。以保證計算速度。

這樣設定既能夠保證我們的最終報是一個使用了multidex模式的,而又不影響我們平時開發的測試效率。

在Android Studio中使用變種App

使用multidex工具構建變種App是非常方便的。在Android Studio允許我們選擇這種變種構建方式的介面。

使用Android Studio構建 “devDebug”構建變種app需要完成兩步:

  • 開啟變種編輯視窗,選擇favorites選項。
  • 點擊編譯不同的變種,如所示 

 

Android分包MultiDex原理詳解

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.