DexKnifePlugin源码解析
Github: DexKnifePlugin 分析版本:9d33ba9
DexKnifePlugin 是一个简单的将指定使用通配符包名分包到第二个dex中gradle插件。
DexKnifePlugin
一个简单的将指定使用通配符包名分包到第二个dex中gradle插件。
同时支持 android gradle plugin 2.2.0 multidex.
使用
在 project 的
build.gradle
添加依赖:1
2
3
4
5
6
7
8
9buildscript {
....
dependencies {
....
classpath 'com.android.tools.build:gradle:2.2.0-beta2' // or other
classpath 'com.ceabie.dextools:gradle-dexknife-plugin:1.5.6'
}
}注意,请确保使用的gradle版本和android gradle plugin兼容,否则会出现同步错误,例如:Gradle sync failed: Unable to load class ‘com.android.builder.core.EvaluationErrorReporter’.
在 app module 下创建
dexknife.txt
,并填写要放到第二个 dex 中的包名路径的通配符:1
Patterns may include: '*' to match any number of characters '?' to match any single character '**' to match any number of directories or files Either '.' or '/' may be used in a pattern to separate directories. Patterns ending with '.' or '/' will have '**' automatically appended.
更多参见: https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/util/PatternFilterable.html
注意: 如果你要过滤内部类, 使用 $* ,例如: SomeClass$*.class
其他配置:
1
使用 # 进行注释, 当行起始加上 #, 这行配置被禁用. # 全局过滤, 如果没设置 -filter-suggest 并不会应用到 建议的maindexlist. # 如果你想要某个包路径在maindex中,则使用 -keep 选项,即使他已经在分包的路径中. -keep android.support.v4.view.** # 这条配置可以指定这个包下类在第二dex中. android.support.v?.** # 使用.class后缀,代表单个类. -keep android.support.v7.app.AppCompatDialogFragment.class # 不包含Android gradle 插件自动生成的miandex列表. -donot-use-suggest # 将 全局过滤配置应用到 建议的maindexlist中, 但 -donot-use-suggest 要关闭. -filter-suggest # 不进行dex分包, 直到 dex 的id数量超过 65536. -auto-maindex # dex 扩展参数, 例如 --set-max-idx-number=50000 # 如果出现 DexException: Too many classes in --main-dex-list, main dex capacity exceeded,则需要调大数值 -dex-param --set-max-idx-number=50000 # 显示miandex的日志. -log-mainlist # 如果你只想过滤 建议的maindexlist, 使用 -suggest-split 和 -suggest-keep. # 如果同时启用 -filter-suggest, 全局过滤会合并到它们中. -suggest-split **.MainActivity2.class -suggest-keep android.support.multidex.**
在 app module 的
build.grade
增加:1
apply plugin: 'com.ceabie.dexnkife'
最后,在 app module 中设置:
1
multiDexEnabled true
注意:要在 defaultConfig 或者 buildTypes中打开 multiDexEnabled true,否则不起作用。
源码解析
因为 DexKnifePlugin 这个工程是一个 gradle 的插件,所以在看源码之前得对 gradle 有一些了解。
DexKnifePlugin
直接看 DexKnifePlugin.groovy
这个文件:
1 | public class DexKnifePlugin implements Plugin<Project> { |
这里就是该插件, apply
便是该插件的入口:
1 | public class DexKnifePlugin implements Plugin<Project> { |
在 gradle 配置阶段完成之后,去判断当前 gradle 插件版本,然后分配去做操作。
我们先来看 1.3.0 的吧
SplitToolsFor130
1 | public class SplitToolsFor130 extends DexSplitTools { |
先找到 dex
这个 task ,然后主要的过程还是在 processMainDexList
中,进行完这个操作之后设置 additionalParameters
参数, processMainDexList
方法在父类 DexSplitTools
中:
DexSplitTools
1 | public class DexSplitTools { |
先通过 getDexKnifeConfig()
来得到配置,然后通过 genMainDexList()
将配置中设置的一些类写入到 maindexlist.txt
中。这里需要注意一下 buildType 的 minifyEnabled,一般在 debug 的时候都没有设置这个参数,默认为 false,当 release 的时候设置该参数为 true,那么会进行混淆工作,所以这里如果该参数为 true 的话直接取读的 mapping 文件。
SplitToolsFor150
1 | public class SplitToolsFor150 extends DexSplitTools { |
主要的 processMainDexList
与 130 的一样,这里就不多说了,再来看看是怎么通过 maindexlist.txt 来实现分包的:
InjectAndroidBuilder
1 | public class InjectAndroidBuilder extends AndroidBuilder { |
通过反射将 AndroidBuilder
替换成自己的,将分包的参数加上,最终是通过 AndroidBuilder#convertByteCode()
写进去的。
总结
- 通过插件的方式很赞,使用的人不需要做太多配置,只需要将插件设置进来便可
- 通过
dexknife.txt
方式来配置也很赞 - 1.5.0 之后的方式很赞
- -split 和 -keep 以及 -suggest-split 和 -suggest-keep 等,参数实在过多