做安卓开发的应该都遇到过这样一个问题:
典型的引用方法超过了65536的错误,构建的时候会报错;
为什么会这样呢?
65536是单个dex文件内可调用的方法数,google用的是个short int;
那dex文件又是什么?
dex文件是之前dalvik虚拟机上执行的文件(5.0开始是AOT),类似jvm虚拟机执行的是字节码文件;
随着应用程序越来越大,包含的方法越来越多,就产生了以上问题,为了解决以上问题:谷歌提供了一些官方的方法:
Android5.0之前的平台版本使用dalvik来执行应用的代码,dalvik限制使用单个dex文件;要想绕过这个限制,使用dalvik可执行文件分包支持库,它会成为主dex文件的一部分,然后管理其他dex文件以及所包含代码的访问。
Android5.0及以上平台使用ART运行时方式,支持从apk文件加载多个dex文件,ART再安装是执行预编译,扫描多个.dex文件,并将它们编译成一个.oat文件,供Android设备执行。
规避64k限制,谷歌提供的方法:
- 首先得先检查大的依赖和传递依赖(怎么检查):确保引用大的依赖所带来的好处大于所带来的弊端。
- 通过ProGuard移除未使用的代码:启用代码压缩,确保交付的apk不含有未使用的代码;(怎么用)
配置应用dalvik可执行文件分包
如果minSdkVersion >=21,只需要在build.gradle文件中,如图:
如果minSdkVersion <=20,除了multiDexEnabled 设置为true,还需要
如果没有替换过Application类,那么
public class MyApplication extends MultiDexApplication { ... }
如果替换过Application,那么
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
配置好之后,Android构建工具会根据需要构建主dex,辅助dex1,辅助dex2等,构建系统会吧所有dex文件打包成apk文件;
分包支持库的局限性:
- 如果辅助dex比较大,可能会引起ANR,在这种情况下,应该用proguard尽量减少dex文件大小;
- 使用 Dalvik 可执行文件分包的应用可能无法在运行的平台版本早于 Android 4.0(API 级别 14)的设备上启动;
- 如果使用 Dalvik 可执行文件分包配置的应用发出非常庞大的内存分配请求,则可能会在运行期间发生崩溃;
声明主dex文件中需要的类
为dalvik可执行文件构建每个dex时,构建工具会执行复杂的决策确定主dex文件中需要的类,如果启动期间需要的任何类未在主 DEX 文件中提供,那么您的应用将崩溃并出现错误 java.lang.NoClassDefFoundError;
如果收到 java.lang.NoClassDefFoundError的错误,则可以用multiDexKeepFile或者multiDexKeepProguard属性声明,以手动将这些类指定为主dex必须项;
multiDexKeepFile属性:
在 multiDexKeepFile 中指定的文件应该每行包含一个类,并且采用如下格式:
com/example/MyClass.class
com/example/MyOtherClass.class
然后,您可以按以下方式针对构建类型声明该文件:
android {
buildTypes {
release {
multiDexKeepFile file('multidex-config.txt')
...
}
}
}
请记住,Gradle 会读取相对于 build.gradle 文件的路径,因此如果 multidex-config.txt 与 build.gradle 文件在同一目录中,以上示例将有效。
multiDexKeepProguard属性
multiDexKeepProguard 文件使用与 Proguard 相同的格式,并且支持整个 Proguard 语法。如需了解有关 Proguard 格式和语法的详细信息;
在 multiDexKeepProguard 中指定的文件应该在任何有效的 ProGuard 语法中包含 -keep 选项;如下:
-keep class com.example.MyClass
-keep class com.example.MyClassToo
如果您想要指定包中的所有类,文件将如下所示:
-keep class com.example.** { *; }
然后,您可以按以下方式针对构建类型声明该文件:
android {
buildTypes {
release {
multiDexKeepProguard('multidex-config.pro')
...
}
}
}