配置方法數超過 64K 的應用(轉)

參考自:developer.android.google.cn/studio/buil… 咱們在開發Androi應用的時候,有時會出現如下這種錯html

//早期版本的構建程序會出現這個錯
Conversion to Dalvik format failed:
Unable to execute dex: method ID not in [0, 0xffff]: 65536
複製代碼

java

//較新版本的 Android 構建系統雖然顯示的錯誤不一樣,但指示的是同一問題
trouble writing output:
Too many field references: 131000; max is 65536.
You may try using --multi-dex option.
複製代碼

這些錯誤都會顯示一個數字:65536。這個數子很重要,他表明的是單個Dalvik Executable(DEX)字節碼文件內的代碼可調用的引用總數。android

關於64K引用限制git

Android 應用 (APK) 文件包含 Dalvik Executable (DEX) 文件形式的可執行字節碼文件,其中包含用來運行您的應用的已編譯代碼。Dalvik Executable 規範將可在單個 DEX 文件內可引用的方法總數限制在 65,536,其中包括 Android 框架方法、庫方法以及您本身代碼中的方法。在計算機科學領域內,術語千(簡稱 K)表示 1024(或 2^10)。因爲 65,536 等於 64 X 1024,所以這一限制也稱爲「64K 引用限制」。github

Android 5.0 以前版本的 Dalvik 可執行文件分包支持

Android 5.0(API 級別 21)以前的平臺版本使用 Dalvik 運行時來執行應用代碼。默認狀況下,Dalvik 限制應用的每一個 APK 只能使用單個 classes.dex 字節碼文件。要想繞過這一限制,您可使用 Dalvik 可執行文件分包支持庫,它會成爲您的應用主要 DEX 文件的一部分,而後管理對其餘 DEX 文件及其所包含代碼的訪問。bash

Android 5.0 及更高版本的 Dalvik 可執行文件分包支持

Android 5.0(API 級別 21)及更高版本使用名爲 ART 的運行時,後者原生支持從 APK 文件加載多個 DEX 文件。ART 在應用安裝時執行預編譯,掃描 classesN.dex 文件,並將它們編譯成單個 .oat 文件,供 Android 設備執行。所以,若是您的 minSdkVersion 爲 21 或更高值,則不須要 Dalvik 可執行文件分包支持庫。 ART和Dalvik介紹app

規避64K限制框架

在將您的應用配置爲支持使用 64K 或更多方法引用以前,您應該採起措施減小應用代碼調用的引用總數,包括由您的應用代碼或包含的庫定義的方法。下列策略可幫助您避免達到 DEX 引用限制:ide

  • 檢查您的應用的直接和傳遞依賴項 - 確保您在應用中使用任何龐大依賴庫所帶來的好處大於爲應用添加大量代碼所帶來的弊端。一種常見的反面模式是,僅僅爲了使用幾個實用方法就在應用中加入很是龐大的庫。減小您的應用代碼依賴項每每可以幫助您規避 dex 引用限制。
  • 經過 ProGuard 移除未使用的代碼 - 爲您的版本構建啓用代碼壓縮以運行 ProGuard。啓用壓縮可確保您交付的 APK 不含有未使用的代碼。

使用這些技巧使您沒必要在應用中啓用 Dalvik 可執行文件分包,同時還會減少 APK 的整體大小。工具

配置您的應用進行 Dalvik 可執行文件分包

若是你的 MinSdkVersion大於等於 21,只須要在模塊級build.gradle文件中將multiDexEnabled設置爲true, 以下:

android {
    defaultConfig {
        ...
        minSdkVersion 21 
        targetSdkVersion 28
        multiDexEnabled true
    }
    ...
}
複製代碼

若是MinSdkVersion小於 21,就比較麻煩了。 須按以下方式使用 Dalvik 可執行文件分包支持庫

  • 修改模塊級 build.gradle 文件以啓用 Dalvik 可執行文件分包,並將 Dalvik 可執行文件分包庫添加爲依賴項,如此處所示:
android {
    defaultConfig {
        ...
        minSdkVersion 15 
        targetSdkVersion 28
        multiDexEnabled true
    }
    ...
}

dependencies {
  compile 'com.android.support:multidex:1.0.3'
}
複製代碼
  • 根據是否要替換 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 可執行文件分包支持庫的侷限性

Dalvik 可執行文件分包支持庫具備一些已知的侷限性,將其歸入您的應用構建配置之中時,您應該注意這些侷限性並進行鍼對性的測試:

  • 啓動期間在設備數據分區中安裝 DEX 文件的過程至關複雜,若是輔助 DEX 文件較大,可能會致使應用無響應 (ANR) 錯誤。在此狀況下,您應該經過 ProGuard 應用代碼壓縮以儘可能減少 DEX 文件的大小,並移除未使用的那部分代碼。
  • 因爲存在 Dalvik linearAlloc 錯誤(問題 22586),使用 Dalvik 可執行文件分包的應用可能沒法在運行的平臺版本早於 Android 4.0(API 級別 14)的設備上啓動。若是您的目標 API 級別低於 14,請務必針對這些版本的平臺進行測試,由於您的應用可能會在啓動時或加載特定類羣時出現問題。代碼壓縮能夠減小甚至有可能消除這些潛在問題。
  • 因爲存在 Dalvik linearAlloc 限制(問題 78035),所以,若是使用 Dalvik 可執行文件分包配置的應用發出很是龐大的內存分配請求,則可能會在運行期間發生崩潰。儘管 Android 4.0(API 級別 14)提升了分配限制,但在 Android 5.0(API 級別 21)以前的 Android 版本上,應用仍有可能遭遇這一限制。

聲明主 DEX 文件中須要的類

爲 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.** { *; }

而後,您能夠按如下方式針對構建類型聲明該文件:

android {
    buildTypes {
        release {
            multiDexKeepProguard('multidex-config.pro')
            ...
        }
    }
}
複製代碼

優化開發構建中的 Dalvik 可執行文件分包

相關文章
相關標籤/搜索