如果移动端访问不佳,请访问 –> Github版

背景

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 页秒开之细节处理 来优化启动体验。

参考资料和推荐阅读:

  • Android Multidex 遇到的问题 (推荐此文)
  • Android的multidex带来的性能问题-减慢app启动速度
  • ClassNotFoundException

总结

这是一篇早就准备写的文章,但当时搜集的资料未及时保存或者丢失,就拖到了现在。因为一个比较旧的 APP 也遇到了相关的问题,所以重新搜集了下资料整理发布出来了,希望能帮到遇到相关问题的朋友们。

PS:你可以通过下面的方式和我联系

  • 微博:cafeting
  • Github: likfe
  • CSDN:他叫自己Mr.张

更多相关文章

  1. android 自定义进度条颜色
  2. 关于android中使用new Message的内存泄露问题
  3. android中如何执行java命令
  4. Android(安卓)开发之旅:又见Hello World!
  5. Android(安卓)学习笔记【基础扫盲篇】
  6. android创建隐藏文件或者文件夹,并对其读写操作
  7. 高通平台android 环境配置编译及开发经验总结【转】
  8. mybatisplus的坑 insert标签insert into select无参数问题的解决
  9. NPM 和webpack 的基础使用

随机推荐

  1. Android常用颜色值
  2. 2.4.4 进度条
  3. 【Android】使用Git控制Android程序的git
  4. 启动 flutter项目时报Could not find com
  5. Android自定义View之一:初探实例
  6. Android通过Uri获取文件的路径的方法
  7. Android(安卓)读取正在运行非系统的程序
  8. Android(安卓)am/pm命令用法
  9. Error:Execution failed for task ':app:
  10. Android(安卓)ListActivity实现遍历文件