先描述一下 我遇到问题的过程。我是负责公司项目的二次开发,之前项目就已经超出64k方法数限制,按照谷歌方法,已经进行了分包处理:
1.在app gradle的defaultConfig 中配置
multiDexEnabled true
2.让自己的定义的application继承MulitiDexApplication(这是我项目中采用的方式),如果你的application已经继承了别的Application 你也可以采用一下这种方式,重写attachBaseContext方法,
@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); MultiDex.install(this); }
3.在app gradle的dependencies中配置,这是谷歌提供的解决安卓5.0一下手机分包适配问题的库
compile 'com.android.support:multidex:1.0.1'
大多数的项目其实采用这些就已经可以正常分包运行了。但是我的项目随着客户的需求增加,引入第三方不断增加,又爆出了
Error:Error converting bytecode to dex:
Cause: com.android.dex.DexException: Too many classes in --main-dex-list, main dex capacity exceeded这个错误,明明已经进行分包了,怎么还出现这种方法数还超出的错误那,经过各种百度,总结得出:
我们采用的是谷歌通用分包方案,既然是通用的当然没有那么智能了,所以它感觉你集成的这些第三方都需要分配在main-dex里面,但其实有些是不需要分配在主Dex里面的,所以这时候就造成了主Dex方法数超出的问题,那怎么解决那?当然还是进行百度了,果然还是有大牛的,终于找到了一套方案,采用dexnkife分包:
1.在project的gradle的defaultConfig 中配置
classpath 'com.ceabie.dextools:gradle-dexknife-plugin:1.5.9'
2.在app的gradle的开头配置
apply plugin: 'com.ceabie.dexnkife'
3.在app目录下创建dexnkife.txt文件,加入分包规则:
# 全局过滤, 如果没设置 -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 -split ** # 将 全局过滤配置应用到 建议的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=65536 # 显示miandex的日志. -log-mainlist # 如果你只想过滤 建议的maindexlist, 使用 -suggest-split 和 -suggest-keep. # 如果同时启用 -filter-suggest, 全局过滤会合并到它们中. -suggest-keep android.support.multidex.**
在这个文件中,我们主要了-donot-use-suggest 和-split ** 这两个方法,就是不使用系统自动给我们分配包的方案,
这也就不会采用之前的主Dex,所以就不会造成主Dex方法数超出问题了,好了,运行一下,没问题,可以正常安装了,你以为
这就完事了?你太单纯了,我刚开始以为这也就Ok了,5.0以上手机运行确实没毛病,但是在5.0以下的手机上安装后,一点应用
就停止运行了。看错误:
Unable to instantiate application com.android.MyApplication:
java.lang.ClassNotFoundException: Didn't find class "com.luck.picture.lib.PictureFileProvider"
on path: DexPathList[dexElements=[zip file "/data/app/com.weyes.focus-1.apk"],
nativeLibraryDirectories=[/data/app-lib/com.weyes.focus-1, /vendor/lib, /system/lib]]
错误显示,应用入口application类找不到?我就去查,可是在反编译的主Dex文件中明明就有这个类为什么还会报出类找不到那?然后就走了弯路,觉得这个dexnkife分包方案,可能对我这个项目不适用,就又去试了网上好多方案都不行,差点绝望了。后来一想应用入口类找不到,不一定是MyApplication类的问题,也可能是这个类中引用的包确实的问题。那怎样才能保证你的入口类中引用的包都在主Dex中那?然后我们再来看一下dexnkife.txt文件,然后我们看一下下面这两个方法:
# 如果你想要某个包路径在maindex中,则使用 -keep 选项,即使他已经在分包的路径中.
-keep android.support.v4.view.**
# 将 全局过滤配置应用到 建议的maindexlist中, 但 -donot-use-suggest 要关闭.
-filter-suggest
这两个方法是使用建议的maindexlist,然后我们把入口的类中引用的文件,全部采用keep分配到主Dex中,然后运行一下。又爆出
主Dex中方法数超出,采用建议的方法出超出,不采用建议的入口类又找不到。然后又浪费好长时间各种尝试,又采用这个方法
# 这条配置可以指定这个包下类在第二dex中.
android.support.v?.**
把maindexlist中感觉启动app用不着的类采用这个方法,主动分配到第二个dex中,可是太多了,,,,最后也是放弃了。最后去
看了一下dexnkife的更新版本日志:惊喜,惊喜,惊喜,,,哈哈哈哈哈
原来在版本1.6.0中支持了如果你在dexnkife.txt中配置了要主动分包到主dex的类,那么maindexlist中就保存这些类。
那么修改一下吧:
在项目的gradle中更改一下引用dexnkife的版本
classpath 'com.ceabie.dextools:gradle-dexknife-plugin:1.6.0'
然后把你入口类MyApplication中类导入的包一个个全部采用keep的方式分配到主Dex中,运行一下。ok了。
这里把自己采坑的记录记录下来,因为解决这个问题,真的浪费掉很多时间。新年假期还在家研究了两天,其实真正了解真的
很简单就可以解决,1.主要自己一直没搞明白dexknife.txt怎么配置 2.就是没有去看dexknife插件介绍。
希望我的记录可以对大家有帮助!
多谢这位大神博客分享:https://www.cnblogs.com/tonny-li/p/7151670.html大神博客