当你的应用程序和库引用达到一定规模,你遇到构建错误显示你的应用已经达到了一个Android应用程序构建体系结构的限制。早期版本的构建系统报告这个错误如下:
Conversion to Dalvik format failed: Unable to execute dex: method ID not in [0, 0xffff]: 65536或者
UNEXPECTED TOP-LEVEL EXCEPTION: java.lang.IllegalArgumentException: method ID not in [0, 0xffff]: 65536 at com.android.dx.merge.DexMerger$6.updateIndex(DexMerger.java:501) at com.android.dx.merge.DexMerger$IdMerger.mergeSorted(DexMerger.java:282) at com.android.dx.merge.DexMerger.mergeMethodIds(DexMerger.java:490) at com.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:167) at com.android.dx.merge.DexMerger.merge(DexMerger.java:188) at com.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main.java:439) at com.android.dx.command.dexer.Main.runMonoDex(Main.java:287) at com.android.dx.command.dexer.Main.run(Main.java:230) at com.android.dx.command.dexer.Main.main(Main.java:199) at com.android.dx.command.Main.main(Main.java:103)
最新版本的Android构建系统显示一个不同的错误,但是是同样一个问题:
trouble writing output: Too many field references: 131000; max is 65536. You may try using --multi-dex option.
或者(我遇到的就是这种)
Error:The number of method references in a .dex file cannot exceed 64K.
上面的错误显示一个共同的数字:65536。这个数字是重要的,它代表了引用的总数,可以在单个调用的代码Dalvik可执行(Dex)字节码文件。如果你的Android应用发生这个错误,恭喜你,你的代码已经达到了一定的量!本文解释了如何解决这个限制并继续构建应用程序。
Android应用程序(APK)在Dalvik可执行文件的形式包含可执行的字节码文件(DEX)文件,其中包含已编译的代码来运行你的应用程序。Dalvik可执行规格限制一个Dex文件包含65536个方法:包括Android框架方法、Library方法的总数、和你自己的代码方法总数。因为65536等于64×1024,这一限制被称为“64k引用限制”。
这个极限就要求我们配置应用程序的构建过程,需要生成多个DEX文件,所以称为multidex 配置。
解决方法分Android 5.0及以上系统和5.0以下系统怎么做。客官们不要着急,先看我一个个分析原因,毕竟我要装下逼哈哈。
Android 5.0(API leve 21)之前的系统使用Dalvik执行应用程序代码。默认情况下,Dalvik限制一个apk只有一个Dex文件。为了绕过这个限制, 我们可以使用multidex support library,它成为我们APK的主要DEX文件的一部分,负责管理我们APK访问其他DEX文件和代码。
注意: 如果咱的项目minSdkVersion是20或更低,运行到Android 4.4(API leve 20)或者更低版本的设备上时需要禁用AndroidStudio的即时运行
Android 5.0(API leve 21)和更高的系统使用runtime是ART ,原生支持从应用的apk文件加载多个DEX文件。ART在安装应用时预编译应用程序,会扫描多个classes(..N).dex文件编译成一个.oat的文件。更多Android5.0 runtime的更多信息,请参见即时运行-instant-run。
注意: 如果你使用即时运行 , AndroidStudio自动配置你的应用程序,你应用程序的minSdkVersion应该设置为21或更高。因为即时只工作在你APP的Debug版本,你任然需要配置你的release版本构建时用multidex避免64k的限制。
在配置我们的App启用64k或者更多方法引用之前,我们可以减少应用代码内的调度总数,包括我们自身应用的方法和第三方的库,下面的几个策略或许可以帮到你:
- 检查你的APP的直接和间接的过度依赖关系:有时候我们用到某个Libaray的某几个方法或者功能时这个库非常大,减少这种依赖可能对与避免64k的问题非常有效。
- 在正式打包构建的时候,使用代码混淆器ProGuard混淆移除未使用的代码,也就是不把没有使用的代码打包到我们的apk中。
使用上面的方法可以帮助我们避免在应用程序中生成太多无用的方法和减小我们apk的大小,这对于用自己服务器做app更新升级的同学是非常有帮助的。
这里给大家推荐下任玉刚同学的插件式开发框架:https://github.com/singwhatiwanna/dynamic-load-apk,共同参与开发者:田啸,宋思宇。
在Android SDK Build Tools 21.1
或者更高版本的build工具中用Android plugin gradle
。确保你更新Android SDK build tools
和Android support
到最新版本,然后用multidex配置应用程序。我们必须要做两步。
在gradle中依赖multidex
,并启用multiDexEnable
:
android { compileSdkVersion 21 buildToolsVersion defaultConfig { ... minSdkVersion 14 targetSdkVersion 21 ... // Enabling multidex support. multiDexEnabled true } ... } dependencies { compile 'com.android.support:multidex:1.0.1' }
android.support.multidex.MultiDexApplication
类 第一种情况,如果我们的APP没有重写过Application类,我们直接继承MultiDexApplication
,然后在manifest.xml中注册Application即可。
第二种情况,如果我们已经重写过Application类,重写attachBaseContext(Context)
方法,并调用MultiDex.install(this);
即可:
protected void attachBaseContext(Context base) { super.attachBaseContext(base); MultiDex.install(this);
因为我翻过MultiDexApplication
的源码了,里面就是重写了这个方法而已哈哈:
public class MultiDexApplication extends Application { public MultiDexApplication() { } protected void attachBaseContext(Context base) { super.attachBaseContext(base); MultiDex.install(this); } }
<?xml version= encoding=?> <manifest xmlns:android= package=> <application ... android:name="刚才重写的Application全类名"> ... </application> </manifest>
一、因此如果应用中包含lirary工程,可能会发生如下错误:
UNEXPECTED TOP-LEVEL EXCEPTION: com.android.dex.DexException: Library dex files are not supported in multi-dex mode
这个时候我们需要禁用预编译:
android { ... dexOptions { preDexLibraries = false } ... }
二、如果在运行的时候遇到如下错误:
UNEXPECTED TOP-LEVEL ERROR: java.lang.OutOfMemoryError: Java heap space
我们需要加大java堆内存大小:
maxProcessCount 4 // this is the default value javaMaxHeapSize "2g"
三、提升运行速度
在Android leve 21或者更高SDK版本。使用ART-supported格式生成multidex输出更快,为我们节省时间,所以我们不必在调试的使用也兼容到5.0以下,所以我们配置最低版本的时候做个如下兼容:
android { productFlavors { // 自定义偏好设置. dev { // 在Android leve 21或更高版本编译更快 minSdkVersion 21 } prod { // 真正的生产环境. minSdkVersion 14 } } ... } dependencies { compile 'com.android.support:multidex:1.0.1' }
你需要添加 以下依赖 multidex-instrumentation :
dependencies { androidTestCompile('com.android.support:multidex-instrumentation:1.0.1') { exclude group: 'com.android.support', module: 'multidex' } }
Eclipse Jar包下载:http://download.csdn.net/detail/yanzhenjie1003/9566518
官方参考文档:https://developer.android.com/tools/building/multidex.html