multidex分包续:将指定的类打包到主dex中

转载:http://blog.csdn.net/gaozhan_csdn/article/details/52024497

参考资料:《Android开发艺术探索》 
本博文中会有一些任玉刚大神的原话以及书中的源码。

前言:在有书上的例子和各种博客的前提下,我还是搞了一整天才成功,各种错误,无语了。总结一下学习的结果,欢迎各位大神指出错误。

一、为什么有将指定的类放入主dex中的需求

我们分包的时候会遇到一个问题,因为加载和初始化的问题,如果某个类不在主dex中,那么程序就会报错,java.lang.NoClassDefFoundError

例如:自定义主dex所包含类的过程中,有9个类必须在主dex中

android/support/multidex/MultiDex.class
android/support/multidex/MultiDexApplication.class
android/support/multidex/MultiDexExtractor.class
android/support/multidex/MultiDexExtractor$1.class
android/support/multidex/MultiDex$4.class
android/support/multidex/MultiDex$14.class
android/support/multidex/MultiDex$19.class
android/support/multidex/ZipUtil.class
android/support/multidex/ZipUtil$CentralDirectory.class
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

这9个类必须在主dex中,否则就会出现异常,就是上面说的找不到类。在attachBaseContext方法中有个MultiDex.install(this),用来加载其他的dex文件,如果MultiDex的相关类不在主dex中,那么这些无法加载,就会报错。

注意:并不是只有这9个类是必须的,我在maindexlist.txt(这个文件做什么后面介绍)中只加入了这9个类和一个MainActivity.class,报出了找不到android/support/multidex/MultiDex$14.class的异常,明明加入了。后来我复制了一个文件,里面有很多类,同时也有这9个类,然后就没有出异常,所以我猜测,这九个类应该还需要其他的一些类。至于复制的什么文件,下面会有介绍。

那么我们为了解决这个找不到类的问题,就必须将这样的类放入主dex中。那么如何将一个类放入主dex中呢?

二、Gradle中的配置

我们需要通过修改build.gradle文件,增加afterEvaluate区域。下面给出完整的build.gradle配置,其中1,3两项配置在dex分包方案概述与multidex包的配置使用中已经介绍过,配置如下:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "22.0.1"

    defaultConfig {
        applicationId "com.example.gao.delete"
        minSdkVersion 17
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
        //1
        multiDexEnabled true
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}
//2
afterEvaluate {
    tasks.matching {
        it.name.startsWith('dex')
    }.each { dx ->
       def listFile = project.rootDir.absolutePath+'/app/maindexlist.txt'
        if (dx.additionalParameters == null) {
            dx.additionalParameters = []
        }
        //表示当方法数越界时则生成多个dex文件(我的没有越界,貌似也生成了两个)
        dx.additionalParameters += '--multi-dex'
        //这个指定了listFile中的类(即maindexlist.txt中的类)会打包到主dex中,不过注意下一条。
        dx.additionalParameters += '--main-dex-list=' +listFile
        //表明只有-main-dex-list所指定的类(在我的配置中,就是app目录下的maindexlist.txt中包含的类)才能打包到主dex中,如果没有这个选项,上个选项就会失效
       dx.additionalParameters += '--minimal-main-dex'
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:24.0.0-alpha1'
    //3
    compile 'com.android.support:multidex:1.0.0'
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

三、创建主dex包含类的列表

为了方便,Demo下只有三个类:

这里写图片描述

根据上面builde.gradle中的配置,我们在app目录下创建一个maindexlist.txt,我们在这个txt里将我们想要放在主dex中的类写进去,自己写还是相当麻烦的,可是自己又不会脚本自动生成,没办法。不过注意一点,由于上述的配置,只有这个txt下的类才会放到主dex中,所以这个文本不能乱写,要不然各种错误,切身体会。。。

  • 我是取巧,在\app\build\intermediates\multi-dex\debug目录下找到了一个maindexlist.txt,注意,这个你改了没用,一运行又恢复了,将这个复制到app目录下,就是配置中listFile指定的路径,然后这个里面默认有很多的类,包括MainActivity,但不包括我们的Fifth.class和Sixth.class,运行,解压apk中的主dex文件,反编译,结果如下:

    这里写图片描述

  • 下面我们在app目录下的maindexlist.txt中增加一行 
    com/example/gao/delete/Sixth.class 
    ,然后重新运行,找到apk,解压,发现分了两个dex文件,我们将主dex文件反编译,主dex反编译结果如下:

    这里写图片描述

    我们可以看到,Sixth.class已经成功加入到主dex中了。

注意:

在\app\build\intermediates\multi-dex\debug目录下的maindexlist.txt复制到app目录下,不更改就只有MainActivity和一些其他类,不包括我们的Fifth.class和Sixth.class。如果我们要增加Sixth.class,如下,我们在第一行增加Sixth.class: 
这里写图片描述

如果改变并保存这个txt,这个txt就会变得很乱(不知道为什么),然后运行就失败,我是一个个回车调整成如图的格式.


猜你喜欢

转载自blog.csdn.net/qq_24451593/article/details/79554372