Multidex記錄一:介紹和使用
為什麼要用記錄呢,因為我從開始接觸Android時我們的專案就在65535的邊緣。不久Google就出了multidex的解決方案。我們也已經接入multidex好多年,但我自己還沒有接入,所以本博文只是作者自己對multidex接入整理記錄其中大部分來源於 ofollow,noindex">Google官網 。

背景
隨著 Android 平臺的持續成長,Android 應用的大小也在增加。當您的應用及其引用的庫達到特定大小時,您會遇到構建錯誤,指明您的應用已達到 Android 應用構建架構的極限。早期版本的構建系統按如下方式報告這一錯誤:
Conversion to Dalvik format failed:Unable to execute dex: method ID not in [0, 0xffff]: 65536
超過最大方法數限制的問題,是由於DEX檔案格式限制,一個DEX檔案中method個數採用使用原生型別short來索引檔案中的方法,也就是2個位元組共計最多表達65536個method,field/class的個數也均有此限制。對於DEX檔案,則是將工程所需全部class檔案合併且壓縮到一個DEX檔案期間,也就是Android打包的DEX過程中, 單個DEX檔案可被引用的方法總數(自己開發的程式碼以及所引用的Android框架、類庫的程式碼)被限制為65536。
Google官方: 配置方法數超過 64K 的應用
Android 5.0 之前版本的 Dalvik 可執行檔案分包支援
Android 5.0(API 級別 21)之前的平臺版本使用 Dalvik 執行時來執行應用程式碼。預設情況下,Dalvik 限制應用的每個 APK 只能使用單個 classes.dex 位元組碼檔案。要想繞過這一限制,您可以使用 multidex
,然後管理對其他 DEX 檔案及其所包含程式碼的訪問。
Android 5.0 及更高版本的 Dalvik 可執行檔案分包支援
Android 5.0(API 級別 21)及更高版本使用名為 ART 的執行時,後者原生支援從 APK 檔案載入多個 DEX 檔案。ART 在應用安裝時執行預編譯,掃描 classesN.dex
檔案,並將它們編譯成單個 .oat
檔案,供 Android 裝置執行。因此,如果您的 minSdkVersion
為 21 或更高值,則不需要 Dalvik 可執行檔案分包支援庫。
現在的Android裝置市場還有大部分的 Android5.0
一下的手機,所以我們要使用 multidex
來解決應用在這些裝置上的 65535
。
配置您的應用進行 Dalvik 可執行檔案分包
將您的應用專案設定為使用 Dalvik 可執行檔案分包配置需要對您的應用專案進行以下修改,具體取決於應用支援的最低 Android 版本。
修改gradle配置檔案
如果您的 minSdkVersion
設定為 21 或更高值,您只需在模組級 build.gradle
檔案中將 multiDexEnabled
設定為 true,如此處所示:
android { defaultConfig { ... minSdkVersion 21 targetSdkVersion 26 multiDexEnabled true } ... }
但是,如果您的 minSdkVersion 設定為 20 或更低值,則Gradle 構建指令碼依賴關係識別符號如下所示:
compile 'com.android.support:multidex:1.0.2'
修改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 可執行檔案分包支援庫的侷限性
- 在冷啟動時因為需要安裝DEX檔案,如果DEX檔案過大時,處理時間過長,很容易引發ANR(Application Not Responding);
- 採用MultiDex方案的應用可能不能在低於Android 4.0 (API level 14) 機器上啟動,這個主要是因為Dalvik linearAlloc的一個bug ;
- 採用MultiDex方案的應用因為需要申請一個很大的記憶體,在執行時可能導致程式的崩潰,這個主要是因為Dalvik linearAlloc 的一個限制,這個限制在 Android 4.0 (API level 14)已經增加了, 應用也有可能在低於 Android 5.0 (API level 21)版本的機器上觸發這個限制。
java.lang.NoClassDefFoundError
為 Dalvik 可執行檔案分包構建每個 DEX 檔案時,構建工具會執行復雜的決策制定來確定主要 DEX 檔案中需要的類,以便應用能夠成功啟動。如果啟動期間需要的任何類未在主 DEX 檔案中提供,那麼您的應用將崩潰並出現錯誤 java.lang.NoClassDefFoundError
。
該情況不應出現在直接從應用程式碼訪問的程式碼上,因為構建工具能識別這些程式碼路徑,但可能在程式碼路徑可見性較低(如使用的庫具有複雜的依賴項)時出現。例如,如果程式碼使用自檢機制或從原生程式碼呼叫 Java 方法,那麼這些類可能不會被識別為主 DEX 檔案中的必需項。
因此,如果您收到 java.lang.NoClassDefFoundError
,則必須使用構建型別中的 multiDexKeepFile
或 multiDexKeepProguard
屬性宣告它們,以手動將這些其他類指定為主 DEX 檔案中的必需項。如果類在 multiDexKeepFile
或 multiDexKeepProguard
檔案中匹配,則該類會新增至主 DEX 檔案。
multiDexKeepFile 屬性
您在 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 屬性
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.** { *; } // All classes in the com.example package
然後,您可以按以下方式針對構建型別宣告該檔案:
android { buildTypes { release { multiDexKeepProguard 'multidex-config.pro' ... } } }
文章到這裡就全部講述完啦,若有其他需要交流的可以留言哦~!~!
想閱讀作者的更多文章,可以檢視我個人部落格 和公共號:
