Android App的大小随着Android平台持续增长。当你的应用程序和它引用的库达到某个大小,你会遇见预示你的App已经达到Android应用构建架构极限的构建错误。早期版本的构建系统报告如下错误:
- Conversion to Dalvik format failed:
- Unable to execute dex: method ID not in [0, 0xffff]: 65536
- trouble writing output:
- Too many field references: 131000; max is 65536.
- You may try using --multi-dex option.
注意:本文档提供的指导取代了在Android开发者博客中发布的Custom Class Loading in Dalvik指导。
大约65千引用限制
—————————————————————————————————————————
Android应用文件(APK)包以含Davik Executable形式(DEX)的可执行字节码文件,它包含了用于你应用执行的编译代码。Davik Executable规范限制在一个DEX文件中可以被调用的方法的总数为65536,包含Android framework方法,库方法,和你自己的代码方法。为了打破这个限制要求,你可以配置你的应用构建进程生成多个DEX文件,被称为multidex配置。
Android5.0之前的Mutidex支持
Android5.0之前的平台版本使用Dalvik运行时执行应用代码。默认,Dalvik限制应每个APK只有一个classes.dex字节码文件。为了绕过这个限制,你可以使用multidex support library,它开始启动你的应用的主要DEX文件,然后控制访问额外的DEX文件和它们的代码;
Android5.0和更高的Mutidex支持
Android5.0和更高使用一个称为ART的运行时,它天然的支持应用APK文件多个dex文件。ART在应用安装时执行预编译,它扫描classes(…N).dex文件并且将它们编译成一个.oat文件在Android设备上执行。更多关于Android5.0运行时的信息,请查阅introducing ART。
避免65K限制
—————————————————————————————————————————
在配置你的应用程序启动使用超过65K方法引用之前,你应该采取措施来减少你的应用代码调用引用的总数,
包含你的应用代码或者包含库的方法定义。下面的策略能帮助你避免突破dex引用限制:
-
检查你的应用的直接和传递依赖-确保在你的应用中你包含的任何大的库依赖以某种方式被使用,那么被添加到应用程序中的代码数量偏大。相反面就是由于很少的实体方法是有用的而包含一个非常大的库。减少你的应用代码依赖通常能帮助你避免dex引用限制。
-
使用ProGuard移除没有使用的代码-为你的应用配置ProGuard设置运行ProGuard,并且确保你为release构建启动了压缩。启动压缩确保你没有在你的APK中装载没有使用的代码。
使用这些技术能帮助你在你的应用中避免为了启动更多的方法引用,而要求的配置改变。这些不能也能减少你的APK的大小,它对带宽成本特别高的市场来说特别重要。
在Gradle中配置你的应用支持Multidex
—————————————————————————————————————————
在Android SDK Build Tools 21.1和更高提供的Android Gradle插件,支持multidex作为你的构建配置的一部分。在为你的应用尝试配置multidex之前,确保你更新了Android SDK Build Tools并且Android Support Repository是最新的版本。
设置你的应用程序开发项目使用multidex配置指需要你的应用开发项目做很小的改动。你需要执行下面的步骤:
-
改变你的Gradle构建配置来启动multidex
-
修改你的清单文件引用MultiDexApplication类
就像下面Gradle构建文件代码段中展示的,修改你的应用的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'
- }
在你的清单文件中添加MultiDexApplication类,从multidex支持库添加到你的应用程序元素。
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.android.multidex.myapplication">
- <application
- ...
- android:name="android.support.multidex.MultiDexApplication">
- ...
- </application>
- </manifest>
注意:如果你的应用使用继承Application类,你可以覆盖attachBaseContext()方法和调用MultiDex.install(this)来启动multidex。更多的信息,请查阅MultiDexApplication参考文档。
multidex支持库的局限
—————————————————————————————————————————
multidex支持库有一些总所周知的局限,那么当你向你的应用构建配置中引入它的时候应该关注并测试它:
-
在启动到一台设备的数据分组时,.dex文件的安装是复杂的,并且如果第二个dex文件非常大,可能导致应用程序无法响应(ANR)错误。在这种情况下,你应该使用ProGuard代码缩减技术来减少dex文件的大小,并且移除未使用部分的代码。
-
使用multidex的应用程序可能在比Android4.0(API Level 14)更早的
… …
优化Multidex开发构建
—————————————————————————————————————————
multidex配导致构建处理的时间显著的增加,因为构建系统必须做出复杂的决策,关于什么类必须被包含在最初的Dex文件中,和什么类能被包含在第二个Dex文件。这就意味着使用multidex的日常构建,作为开发过程的一部分被执行的更长,并且会减缓你的开发进程。
为了multidex输出减轻更长的构建时间,你应该使用Android Gradle插件productFlavors:在你的构建输出上创建两个变量:一个开发Flavor和一个生产flavor。
对于开发Flavor,设置最小的SDK版本为21。这个设置使用支持ART格式生成multidex输出更快。对于生成Flavor,设置最低的SDK版本和你实际支持的最小级别一样。这个设置生成一个兼容更多设备的multidex APK,但是花费更长时间来构建。
下面的构建配置例子演示了如何在Gradle构建文件中设置这些Flavor:
- android {
- productFlavors {
- // Define separate dev and prod product flavors.
- dev {
- // dev utilizes minSDKVersion = 21 to allow the Android gradle plugin
- // to pre-dex each module and produce an APK that can be tested on
- // Android Lollipop without time consuming dex merging processes.
- minSdkVersion 21
- }
- prod {
- // The actual minSdkVersion for the application.
- minSdkVersion 14
- }
- }
- ...
- buildTypes {
- release {
- runProguard true
- proguardFiles getDefaultProguardFile('proguard-android.txt'),
- 'proguard-rules.pro'
- }
- }
- }
- dependencies {
- compile 'com.android.support:multidex:1.0.0'
- }
-
构建应用程序的每个模块(包含依赖)作为单独的dex文件。这通常被称为pre-dexing。
-
在API中包含未修改的每个dex文件。
-
最重要的是,module dex文件不会被结合,和决定最初的dex文件内容的大量时间被避免。
这些设置使得快速、增量构建,因为仅仅被修改模块的dex文件被重新计算,并且打包到APK文件中。这些设置产生的APK仅仅能被用在Android5.0设备上测试。然而,通过实现了flavor形式的设置,你保留了在合适的生产最新SDK级别和proguard设置执行正常构建的能力。
你也能构建其它的实体,包含一个proDebug实体构建,他花费更长的时间,但是能被用于测试以外的开发。
… …
在Android Studio中使用构建实体
构建实体对于管理构建进程什么时候使用multidex非常有用。Android允许你在用户界面选择这些构建实体。
为了让Android Studio构建你的应用的"devDebug"实体:
-
在左侧栏中打开Build实体窗口,选项位于Favorites旁边。
-
点击构建实体的名字来选择不同的实体,如图1所示。
注意:打开窗口中的选项仅仅在你使用Tools>Android>Sync Project with Gradle Files命令,使用你的Gradle构建文件成功同步Android Studio之后才有效。
测试Multidex应用
—————————————————————————————————————————
测试使用了multidex配置的应用需要一些额外的步骤和配置。因为类的代码位置没有在一个单独的DEX文件中,instrumentation测试无法正常运行,除非配置支持multidex。
当测使用instrumentation测试一个multidex应用的时候,使用来自multidex测试支持库中的MultiDexTestRunner。下面的build.gradle文件例子,演示了如何配置你的构架使用这个test runner:
- android {
- defaultConfig {
- ...
- testInstrumentationRunner "android.support.multidex.MultiDexTestRunner"
- }
- }
- dependencies {
- androidTestCompile 'com.android.support:multidex-instrumentation:1.0.0'
- }
- public void onCreate(Bundle arguments) {
- MultiDex.install(getTargetContext());
- super.onCreate(arguments);
- ...
- }