Android 分Dex (MultiDex)

需要分Dex的理由想必大家都知道了.正是在ART以前的Android系统中,Dex文件对于方法索引是用一个short类型的数据来存放的.而short的最大值是65535,因此当项目足够大包含方法数目足够多超过了65535(包括引用的外部Lib里面的所有方法),当运行App,就会得到如下的错误提示.

Unable to execute dex: method ID not in [0, 0xffff]: 65536
Conversion to Dalvik format failed: Unable to execute dex: method ID not in [0, 0xffff]: 65536

这个致命严重的Bug出现后,Android官方就写了一篇著名的Blog(这篇文章我读了五六遍,甚至连作者的Google+的照片我都看了两三次,我还是没有完全搞明白怎么Walkaround这个严重的问题).

再后来,慢慢发展,有很多能人异士发挥自己的创造力,写了开源的Lib放在GitHub上分享给其他Android开发者们使用.HelloMultiDex, Secondary-Dex-Gradle等等.

但是解铃还须系铃人,这种系统性的严重致命Bug,当然还是Android官方给出解决方案最让人放心.终于,我们还是等到了你,MultiDex Offical Solution.

我推荐官方文档这篇GitHub的文章一起看会有更好的了解,少走弯路.

下面说一说使用的步骤:

1. 修改Gradle,导入‘com.android.support:multidex:1.0.0‘,打开multiDexEnabled;

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‘
}

2.修改Application.两种方法:

1) 直接把Application替换成MultiDexApplication

<?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>

2) 在原来的Application中修改调用MultiDex.install(this);

public class HelloMultiDexApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);
    }
}

到这里其实MultiDex的配置已经完成了.

但是,实际上下面介绍的几个问题也非常值得我们关注.

1. 一些在二级Dex加载之前,可能会被调用到的类(比如静态变量的类),必须放在主Dex中.否则会ClassNotFoundError.

通过修改Gradle,可以显示的把一些类放在Main Dex中.

afterEvaluate {
    tasks.matching {
        it.name.startsWith(‘dex‘)
    }.each { dx ->
        if (dx.additionalParameters == null) {
            dx.additionalParameters = []
        }
        dx.additionalParameters += ‘--multi-dex‘
        dx.additionalParameters += "--main-dex-list=$projectDir/<filename>".toString()
    }
}

上面是修改后的Gradle,其中<filename>是一个文本文件的文件名,存放在和这个Gradle脚本同一级的文件目录下.

而这个文本文件的内容如下.实际就是把需要放在Main Dex的类罗列出来.

android/support/multidex/BuildConfig/class
android/support/multidex/MultiDex$V14/class
android/support/multidex/MultiDex$V19/class
android/support/multidex/MultiDex$V4/class
android/support/multidex/MultiDex/class
android/support/multidex/MultiDexApplication/class
android/support/multidex/MultiDexExtractor$1/class
android/support/multidex/MultiDexExtractor/class
android/support/multidex/ZipUtil$CentralDirectory/class
android/support/multidex/ZipUtil/class

2. 如果用使用其他Lib,要保证这些Lib没有被preDex,否则可能会抛出下面的异常

UNEXPECTED TOP-LEVEL EXCEPTION:
    com.android.dex.DexException: Library dex files are not supported in multi-dex mode
        at com.android.dx.command.dexer.Main.runMultiDex(Main.java:337)
        at com.android.dx.command.dexer.Main.run(Main.java:243)
        at com.android.dx.command.dexer.Main.main(Main.java:214)
        at com.android.dx.command.Main.main(Main.java:106)

遇到这个异常,需要在Gradle中修改,让它不要对Lib做preDexing

android {
//  ...
    dexOptions {
        preDexLibraries = false
    }
}

3. 如果每次都打开MultiDex编译版本的话,会比平常用更多的时间(这个也容易理解,毕竟做了不少事情)

Android的官方文档也给了我们一个小小的建议,利用Gradle建立两个Flavor.一个minSdkVersion设置成21,这是用了ART支持的Dex格式,避免了MultiDex的开销.而另外一个Flavor就是原本支持的最小sdkVersion.平时开发时候调试程序,就用前者的Flavor,发布版本打包就用后者的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‘
}

有了Android官方的支持后,MultiDex比最原始的解决方案简单多了.妈妈再也不用担心我们要分Dex啦!

时间: 2024-10-17 10:35:52

Android 分Dex (MultiDex)的相关文章

android 傻瓜式 MultiDex 插件,从此再也不用担心方法数问题!

ndroid-Easy-MultiDex 项目地址:TangXiaoLv/Android-Easy-MultiDex 简介:Android 傻瓜式 MultiDex 插件,从此再也不用担心方法数问题! 注 1:不想看前半部分的话可以直接跳过到最下面配置部分.注 2:本插件是基于DexKnifePlugin 1.5.6优化改造而来,感谢 ceabie 的无私奉献. 填坑之路 坑 1:65536 ,So easy! 原因:Dalvik 的 invoke-kind 指令集中,method refere

Android兼容包multidex的开发和构建方法

在Android开发中,函数方法超过65k限制后,我们就常常会用到multidex分包解决,但是multidex的配置,对系统apk的构建.签名.打包复杂性大大的增加,严重的降低了构建效率.那这个问题怎么处理呢? 为解决这个问题,通常我们使用的方法就是在Gradle productFlavors新建出来一个 development flavor 和 production flavor 来满足我们不同构建需求. 为了更直观的给大家展示具体的操作,我们通过一个例子来演示如何设置这些flavors在G

smali An assembler/disassembler for Android&#39;s dex format

TypesMethodsAndFields - smali - Some general information about how types, methods and fields are represented in dalvik bytecode - An assembler/disassembler for Android's dex format - Google Project Hosting TypesMethodsAndFields Some general informati

解决Android单个dex文件不能超过65535个方法问题

一.找坑:谷歌规定单个dex文件中的方法不能超过65536的限制 我们编写项目过程中在工程的lib文件夹下引用的第三方插件jar包太多或者项目过大,编译运行时就有可能报出com.android.dex.DexIndexOverflowException: method ID not in [0, 0xffff]: 65536错误.看到这个错误说明你的方法加起来已经超过了65536这个数目.但是谷歌规定单个dex文件中的方法不能超过65536的限制. 如下图所示,Android Studio 中的

Android &quot;multiple dex files define&quot; 错误

在Android开发中经常看到这个错误,产生的原因还是挺值得研究的. 如果是在eclipse上出现的这个问题,基本上可以判断为同一工程中存在相同的jar包,或者是不同的jar包,但是他们之间有相同的类,所以解决办法就是干掉对方. 在eclipse中如果删除jar之后还报错的话,可能是eclipse的缓存导致的,重启eclipse基本可以解决这个问题. 但是如果事情发生在 Android Studio 上,那么就复杂了.首先要排除eclipse中的那种情况,如果问题还没有解决那就要仔细了. 如果工

Android分屏显示LogCat

Eclipse里有很多界面组件,文件列表.编辑区.类结构等等,在这么多界面组件里,再打开一个Logcat就基本没有什么空间了.与其挤在一起还不如分开成两个窗口. 或者你有两个屏幕,想一个屏幕编辑,一个屏幕看log. 总之,目的是让Logcat分屏. 尝试了下在Eclipse里实现这个功能,不太容易.但是我们可以单独打开一个DDMS窗口,查看logcat. 打开Android SDK的目录,打开 /tools/ddms.bat ,这时就打开单独的一个DDMS窗口. 最大化它,享受分屏查看log的快

android多dex打包问题

将android-support-multidex.jar放到libs下然后编译,出现如下错误: Error:Execution failed for task ':app:packageAllDebugClassesForMultiDex'. > java.util.zip.ZipException: duplicate entry: android/support/multidex/MultiDex.class 原因是引入了多个相同的包,但是libs下明明就只有这一个包啊,经过各种尝试,最终

【Android SDK程序逆向分析与破解系列】之二:Android可执行程序DEX分析(一)

作者:郭嘉 邮箱:[email protected] 博客:http://blog.csdn.net/allenwells github:https://github.com/AllenWells [Android SDK程序逆向分析与破解系列]章节索引 一 DEX文件数据结构 DEX使用的数据类型如下表所示: u1~u8:表示1~8字节的无符号数. sleb128.uled128和uled128pl:DEX文件特有的LEB128数据类型.每个LEB128由1~5个字节组成,所有的字节组合在一起

解决Android单个dex文件不能超过65536个方法问题

当我们的项目代码过大时,编译运行时会报Unable to execute dex: method ID not in[0, 0xffff]: 65536)错误.当出现这个错误时说明你本身自己的工程代码中含有的太多的方法,或者你的工程lib文件夹下引用的第三方插件jar包有太多的方法,这两者的方法加起来已经超过了65536这个数目.而谷歌规定单个dex文件中的方法不能超过65536的限制. 那么这个时候,我们就需要分包处理解决.一般情况下的解决方案就是把整个项目工程包括jar,区分开来分解成两个d