}
Dex merged = new DexMerger(dexes.toArray(new Dex[dexes.size()]), CollisionPolicy.FAIL).merge();
return merged.getBytes();
}
}
这里可以看到变量 libraryDexBuffers ,是一个 List 集合,那么我们看一下这个集合在哪里添加数据的:
public class Main {
private static boolean processFileBytes(String name, long lastModified, byte[] bytes) {
boolean isClassesDex = name.equals(DexFormat.DEX_IN_JAR_NAME);
//blablabla…
} else if (isClassesDex) {
synchronized (libraryDexBuffers) {
libraryDexBuffers.add(bytes);
}
return true;
} else {
//blablabla…
}
//调用processFileBytes的地方
private static class FileBytesConsumer implements ClassPathOpener.Consumer {
@Override
public boolean processFileBytes(String name, long lastModified,
byte[] bytes) {
return Main.processFileBytes(name, lastModified, bytes);
}
//blablabla…
}
//调用FileBytesConsumer的地方
private static void processOne(String pathname, FileNameFilter filter) {
ClassPathOpener opener;
opener = new ClassPathOpener(pathname, true, filter, new FileBytesConsumer());
if (opener.process()) {
updateStatus(true);
}
}
//调用processOne的地方
private static boolean processAllFiles() {
//blablabla…
// forced in main dex
for (int i = 0; i < fileNames.length; i++) {
processOne(fileNames[i], mainPassFilter);
}
//blablabla…
}
//调用processAllFiles的地方
private static int runMonoDex() throws IOException {
//blablabla…
if (!processAllFiles()) {
return 1;
}
//blablabla…
}
}
跟了一圈又跟回来了,但是注意一个变量:fileNames[i],传进去这个变量,是个地址,最终在 processFileBytes 中处理后添加到 libraryDexBuffers 中,那跟一下这个变量:
public class Main {
private static boolean processAllFiles() {
//blablabla…
String[] fileNames = args.fileNames;
//blablabla…
}
public void parse(String[] args) {
//blablabla…
}else if(parser.isArg(INPUT_LIST_OPTION + “=”)) {
File inputListFile = new File(parser.getLastValue());
try{
inputList = new ArrayList();
readPathsFromFile(inputListFile.getAbsolutePath(), inputList);
} catch(IOException e) {
System.err.println("Unable to read input list file: " + inputListFile.getName());
throw new UsageException();
}
} else {
//blablabla…
fileNames = parser.getRemaining();
if(inputList != null && !inputList.isEmpty()) {
inputList.addAll(Arrays.asList(fileNames));
fileNames = inputList.toArray(new String[inputList.size()]);
}
}
public static void main(String[] argArray) throws IOException {
Arguments arguments = new Arguments();
arguments.parse(argArray);
int result = run(arguments);
if (result != 0) {
System.exit(result);
}
}
}
跟到这里发现是传进来的参数,那我们再看看 gradle 里面传的是什么参数吧,查看 Dex task :
public class Dex extends BaseTask {
@InputFiles
Collection libraries
}
我们把这个参数打印出来:
afterEvaluate {
tasks.matching {
it.name.startsWith(‘dex’)
}.each { dx ->
if (dx.additionalParameters == null) {
dx.additionalParameters = []
}
println dx.libraries
}
}
打印出来发现是 build/intermediates/pre-dexed/ 目录里面的 jar 文件,再把 jar 文件解压发现里面就是 dex 文件了。所以 DexMerger 的工作就是合并这里的 dex 。
更改编译环境
buildscript {
//…
dependencies {
classpath ‘com.android.tools.build:gradle:2.1.0-alpha3’
}
}
将 gradle 设置为 2.1.0-alpha3 之后,在项目的 build.gradle 中即使没有设置 multiDexEnabled true 也能够编译通过,但是生成的 apk 包依旧是两个 dex ,我想的是可能为了设置 instantRun 。
解决 65536
Google MultiDex 解决方案:
在 gradle 中添加 MultiDex 的依赖:
dependencies { compile ‘com.android.support:MultiDex:1.0.0’ }
在 gradle 中配置 MultiDexEnable :
android {
buildToolsVersion “21.1.0”
defaultConfig {
// Enabling MultiDex support.
MultiDexEnabled true
}
}
在 AndroidManifest.xml 的 application 中声明:
如果有自己的 Application 了,让其继承于 MultiDexApplication 。
如果继承了其他的 Application ,那么可以重写 attachBaseContext(Context):
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
LinearAlloc
gradle:
afterEvaluate {
tasks.matching {
it.name.startsWith(‘dex’)
}.each { dx ->
if (dx.additionalParameters == null) {
dx.additionalParameters = []
}
dx.additionalParameters += ‘–set-max-idx-number=48000’
}
}
–set-max-idx-number= 用于控制每一个 dex 的最大方法个数。
这个参数在查看 dx.jar 找到:
//blablabla…
} else if (parser.isArg(“–set-max-idx-number=”)) { // undocumented test