Android 項目開發填坑記 - 使用 MultiDex 解決 64K 限制

JewSkene 8年前發布 | 16K 次閱讀 安卓開發 Android開發 移動開發

Android 的 classLoader 在加載 APK 的時候限制了 class.dex 包含的 Java 方法數,其總數不能超過65535(64K, 不要再說成 65K 了,1K = 2^10 = 1024 , 64 * 1024 = 65535),Google 官方給出的解決方案是使用 Multidex

啟用 Multidex

基本要求:

  • 使用 Android Studio 開發工具
  • Android SDK Build Tools >= 21.1
  • 更新 Android Support Repository 到最新版本

配置步驟:

  1. 配置 Gradle build 來開啟 multidex
  2. 修改 manifest 來引用 MultiDexApplication 類

修改 module 下的 build.gradle 文件,添加支持庫并開啟 multidex:

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

PS: compileSdkVersion、buildToolsVersion 根據實際項目配置,但是版本不能低于上述版本。

在 AndroidManifest.xml 中給 application 節點添加對 MultiDexApplication 類的引用:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="xxx">
    <application
 ...
 android:name="android.support.multidex.MultiDexApplication">
        ...
    </application>
</manifest>

PS: manifest 節點的 package 屬性值根據實際項目有所不同。

注意:如果你的 APP 使用了繼承 Application 的類,你需要重寫 attachBaseContext() 方法并調用 MultiDex.install(this) 來啟用 multidex 。

public class XXX extends Application{
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);
    }
}

網上搜到還有一個方法:不繼承 Application ,而是直接繼承 MultiDexApplication 即可,這樣就不需要重寫 attachBaseContext() 方法了。

參考資料: Configure Apps with Over 64K Methods

可能遇到的問題

NoClassDefFoundError

Android SDK Build Tools 21.1 或者更高版本中的 Gradle Android 插件有對 multidex 的支持。這個插件使用 Proguard 來分析你的項目并在 [buildDir]/intermediates/multi-dex/[buildType]/maindexlist.txt 文件中生成一個 app 啟動 classes 的列表。但是這個列表并不是100%準確,可能會丟失一些app啟動所需的 classes 。

如果你在本地的測試機上沒有遇到這個問題,并不代表你的 APP 沒有問題,我通過查看友盟的崩潰記錄和使用一些真機測試平臺來進行檢查,通常情況下會有所發現。

解決方法:在 module 下創建 multidex.keep 文件,并在其中羅列出那些 class,以便讓編譯器知道在 main dex 文件中要保持哪些 class。

生成 multidex.keep 文件中的內容有多種:

方法一:修改 module 下的 build.gradle 文件

apply plugin: 'com.android.application'
android {
  ...
}
dependencies {
  ...
}
android.applicationVariants.all { variant ->
    task "fix${variant.name.capitalize()}MainDexClassList" << {
        logger.info "Fixing main dex keep file for $variant.name"
        File keepFile = new File("$buildDir/intermediates/multi-dex/$variant.buildType.name/maindexlist.txt")
        keepFile.withWriterAppend { w ->
            // Get a reader for the input file
            w.append('\n')
            new File("${projectDir}/multidex.keep").withReader { r ->
                // And write data from the input into the output
                w << r << '\n'
            }
            logger.info "Updated main dex keep file for ${keepFile.getAbsolutePath()}\n$keepFile.text"
        }
    }
}
tasks.whenTaskAdded { task ->
    android.applicationVariants.all { variant ->
        if (task.name == "create${variant.name.capitalize()}MainDexClassList") {
            task.finalizedBy "fix${variant.name.capitalize()}MainDexClassList"
        }
    }
}

方法二:修改 module 下的 build.gradle 文件

apply plugin: 'com.android.application'
android {
  ...
  afterEvaluate {
        tasks.matching {
            it.name.startsWith('dex')
        }.each { dx ->
            if (dx.additionalParameters == null) {
                dx.additionalParameters = []
            }
            dx.additionalParameters += '--multi-dex' // enable multidex

            // optional
            dx.additionalParameters += "--main-dex-list=$projectDir/class-list.txt".toString() // enable the main-dex-list
            dx.additionalParameters += '--minimal-main-dex'
        }
    }
}
dependencies {
  ...
}

使用上述任意方式配置完成后, clean 然后 rebuild 項目,完成之后在 module 下的 build/intermediates/multi-dex/xxx 里找到 maindexlist.txt 文件(如果找不到相關目錄,可能需要你同步后 rebuild 項目才能生成),復制里面的內容到 module 根目錄下 multidex.keep 文件中(沒有則先創建此文件)。

然后,比較重要的一步就是:通過友盟、測試記錄、Bug記錄等獲取到 NoClassDefFoundError 錯誤對應的類,按照 maindexlist.txt 文件的方式添加這些類到 multidex.keep 文件中就可解決了。

其他錯誤和問題

比如 首次安裝啟動時黑屏沒有響應/ANR安裝時異常 等,你可以參考文末的一些文章,此外你還可以參考 Android 必知必會-Android Splash 頁秒開之細節處理 來優化啟動體驗。

參考資料和推薦閱讀:

總結

這是一篇早就準備寫的文章,但當時搜集的資料未及時保存或者丟失,就拖到了現在。因為一個比較舊的 APP 也遇到了相關的問題,所以重新搜集了下資料整理發布出來了,希望能幫到遇到相關問題的朋友們。

PS:你可以通過下面的方式和我聯系

 

來自:http://likfe.com/2016/08/17/android-multiDex/

 

 本文由用戶 JewSkene 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!