关闭

Android 项目开发填坑记 - 使用 MultiDex 解决 64K 限制

标签: android
2631人阅读 评论(2) 收藏 举报
分类:

如果移动端访问不佳,请访问 –> 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 页秒开之细节处理 来优化启动体验。

参考资料和推荐阅读:

总结

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

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

1
0
查看评论

其实你不知道MultiDex到底有多坑

就在前几天,公司正在做的项目遇到了方法数越界的问题,当时真是醉了。想想也难怪,项目中的依赖库就有三十多个,方法数不越界才怪。所以马上上网寻找解决方法,于是找到了下面这篇文章,觉得文章讲解的很全面,所以转载过来,分享给更多的人。最后感谢作者的分享精神。
  • qq_17766199
  • qq_17766199
  • 2016-04-30 11:22
  • 9754

Android 使用android-support-multidex解决Dex超出方法数的限制问题,让你的应用不再爆棚

随着应用不断迭代,业务线的扩展,应用越来越大(比如集成了各种第三方sdk或者公共支持的jar包,项目耦合性高,重复作用的类越来越多),相信很多人都遇到过如下的错误: UNEXPECTED TOP-LEVEL EXCEPTION: java.lang.IllegalArgumentExcept...
  • t12x3456
  • t12x3456
  • 2014-11-10 00:05
  • 157525

关于Android Application类的一些认识

在学习别人的代码时候,发现有一个Application类,趁机了解一下~ 下面是看到的几篇比较好的文章。转载过来学习学习~ 第一篇:Android Application的作用 What is Application Application和Actovotu,Service一样是...
  • Goo_x
  • Goo_x
  • 2016-03-09 19:12
  • 1394

dex分包方案概述与multidex包的配置使用

参考资料: Android dex分包方案 Android分包MultiDex原理 《Android开发艺术探索》博客中间会涉及到dex文件的反编译,参考博文: dex文件的反编译-dex2jar和jd-gui1.dex分包的原因对于功能越来越复杂的app的两大问题 问题一:当项目越来越大,...
  • gaozhan_csdn
  • gaozhan_csdn
  • 2016-07-22 10:06
  • 6308

Android MultiDex 解析与使用

Android MultiDex 解析与使用背景随着你的Apk不断的迭代更新,到你的apk到达一定大小的时候,你在编译apk的时候可能会出现下面的错误
  • k1457047898
  • k1457047898
  • 2016-12-05 17:12
  • 1254

androidstudio MultiDex慎用

遭遇MultiDex 愉快地写着Android代码的总悟君往工程里引入了一个默默无闻的jar然后Run了一下, 经过漫长的等待AndroidStudio构建失败了。 于是总悟君带着疑惑查看错误信息。 UNEXPECTED TOP-LEVEL EXCEPTION:...
  • S1107432915SL
  • S1107432915SL
  • 2016-04-01 14:47
  • 2684

其实你不知道MultiDex到底有多坑

遭遇MultiDex 愉快地写着Android代码的总悟君往工程里引入了一个默默无闻的jar然后Run了一下, 经过漫长的等待AndroidStudio构建失败了。 于是总悟君带着疑惑查看错误信息。 UNEXPECTED TOP-LEVEL EXCEPTION: ja...
  • yangxi_001
  • yangxi_001
  • 2017-02-07 18:25
  • 1277

android MultiDex multiDex原理(一)

android MultiDex 原理(一) Android分包MultiDex原理详解 MultiDex的产生背景 当Android系统安装一个应用的时候,有一步是对Dex进行优化,这个过程有一个专门的工具来处理,叫DexOpt。DexOpt的执行过程是在第一次加载Dex文件的时候执行的。这个过程...
  • DJY1992
  • DJY1992
  • 2016-04-15 15:25
  • 17684

Android MultiDex 解决 64K 限制,方法数超过65535解决方法

参考一下文章: http://www.tuicool.com/articles/aiAf6f http://blog.csdn.net/zhangbuzhangbu/article/details/52770939 https://stackoverflow.com/questions/337870...
  • fan7983377
  • fan7983377
  • 2017-06-28 17:16
  • 1558

Android Multidex 遇到的问题

Android 的classLoader在加载APK的时候限制了class.dex包含的Java方法总数不能超过65535,但是现在随便一个复杂一点的App,轻而易举就能超过65535。为了解决这个问题,google推出了官方的解决方案——Multidex 一、使用之后,相信很多人都遇到过以下几个问...
  • wangbaochu
  • wangbaochu
  • 2016-04-18 14:15
  • 8931
    个人资料
    • 访问:304984次
    • 积分:3557
    • 等级:
    • 排名:第11002名
    • 原创:68篇
    • 转载:8篇
    • 译文:3篇
    • 评论:140条
    博客专栏
    文章分类
    最新评论
    样式调整