随着应用不断迭代,业务线的扩展,应用越来越大(比如集成了各种第三方sdk或者公共支持的jar包,项目耦合性高,重复作用的类越来越多),相信很多人都遇到过如下的错误:

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)

没错,你的应用中的Dex 文件方法数超过了最大值65536的上限,简单来说,应用爆棚了.

那么让我们看一下为什么会引起这种错误:

在Android系统中,一个App的所有代码都在一个Dex文件里面。Dex是一个类似Jar的存储了多有Java编译字节码的归档文件。因为Android系统使用Dalvik虚拟机,所以需要把使用Java Compiler编译之后的class文件转换成Dalvik能够执行的class文件。这里需要强调的是,Dex和Jar一样是一个归档文件,里面仍然是Java代码对应的字节码文件。当Android系统启动一个应用的时候,有一步是对Dex进行优化,这个过程有一个专门的工具来处理,叫DexOpt。DexOpt的执行过程是在第一次加载Dex文件的时候执行的。这个过程会生成一个ODEX文件,即Optimised

Dex。执行ODex的效率会比直接执行Dex文件的效率要高很多。但是在早期的Android系统中,DexOpt有一个问题,也就是这篇文章想要说明并解决的问题。DexOpt会把每一个类的方法id检索起来,存在一个链表结构里面。但是这个链表的长度是用一个short类型来保存的,导致了方法id的数目不能够超过65536个。当一个项目足够大的时候,显然这个方法数的上限是不够的。尽管在新版本的Android系统中,DexOpt修复了这个问题,但是我们仍然需要对低版本的Android系统做兼容.

那么问题来了怎么做兼容呢?我自己的实践是这样的:

1、把一些jar包做成classesX.dex(这里的X代表一个整数从2开始例如:classes2.dex、classes3.dex),把做成的dex文件放到src目录下。这里的命名和存放路径都是由android-support-multidex.jar这个包规定的,我本人也是经过反编译后读程序了解到的。

2、在自己的项目下新建lib目录把需要的jar包放在里边然后在Order and Export里边手动选择jar包,不要勾选已经制作成dex的jar就行了,这一步应该了解Order and Export的作用是什么(解释一下吧作用就是勾选的jar会打进你的应用程序里边,不勾选当然就不会打进去了,这个可以自己反编译apk文件看看就清楚了)。

3、让项目里边原来继承Application的类继承MultiDexApplication就可以了。至于为啥这样做看了android-support-multidex.jar里边的源码就很清楚了,当然了java基础要过关哦。

下面是android-support-multidex.jar的源码:

//MultiDexApplication.java

package android.support.multidex;

import android.app.Application;

import android.content.Context;

// Referenced classes of package android.support.multidex:

//MultiDex

public class MultiDexApplication extends Application

{

public MultiDexApplication()

{

}

protected void attachBaseContext(Context base)

{

super.attachBaseContext(base);

MultiDex.install(this);

}

}

主要是下面MultiDexExtractor这个类可以好好读读会发现很多惊喜的。

//MultiDexExtractor.java

package android.support.multidex;

import android.content.Context;

import android.content.SharedPreferences;

import android.content.pm.ApplicationInfo;

import android.os.Build;

import android.util.Log;

import java.io.*;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

import java.util.ArrayList;

import java.util.List;

import java.util.zip.*;

// Referenced classes of package android.support.multidex:

//ZipUtil

final class MultiDexExtractor

{

private static final String TAG = "MultiDex";

private static final String DEX_PREFIX = "classes";

private static final String DEX_SUFFIX = ".dex";

private static final String EXTRACTED_NAME_EXT = ".classes";

private static final String EXTRACTED_SUFFIX = ".zip";

private static final int MAX_EXTRACT_ATTEMPTS = 3;

private static final String PREFS_FILE = "multidex.version";

private static final String KEY_TIME_STAMP = "timestamp";

private static final String KEY_CRC = "crc";

private static final String KEY_DEX_NUMBER = "dex.number";

private static final int BUFFER_SIZE = 16384;

private static final long NO_VALUE = -1L;

private static Method sApplyMethod;

MultiDexExtractor()

{

}

static List load(Context context, ApplicationInfo applicationInfo, File dexDir, boolean forceReload)

throws IOException

{

Log.i("MultiDex", (new StringBuilder()).append("MultiDexExtractor.load(").append(applicationInfo.sourceDir).append(", ").append(forceReload).append(")").toString());

File sourceApk = new File(applicationInfo.sourceDir);

long currentCrc = getZipCrc(sourceApk);

List files;

if (!forceReload && !isModified(context, sourceApk, currentCrc))

{

try

{

files = loadExistingExtractions(context, sourceApk, dexDir);

}

catch (IOException ioe)

{

Log.w("MultiDex", "Failed to reload existing extracted secondary dex files, falling back to fresh extraction", ioe);

files = performExtractions(sourceApk, dexDir);

putStoredApkInfo(context, getTimeStamp(sourceApk), currentCrc, files.size() + 1);

}

} else

{

Log.i("MultiDex", "Detected that extraction must be performed.");

files = performExtractions(sourceApk, dexDir);

putStoredApkInfo(context, getTimeStamp(sourceApk), currentCrc, files.size() + 1);

}

Log.i("MultiDex", (new StringBuilder()).append("load found ").append(files.size()).append(" secondary dex files").toString());

return files;

}

private static List loadExistingExtractions(Context context, File sourceApk, File dexDir)

throws IOException

{

Log.i("MultiDex", "loading existing secondary dex files");

String extractedFilePrefix = (new StringBuilder()).append(sourceApk.getName()).append(".classes").toString();

int totalDexNumber = getMultiDexPreferences(context).getInt("dex.number", 1);

List files = new ArrayList(totalDexNumber);

for (int secondaryNumber = 2; secondaryNumber <= totalDexNumber; secondaryNumber++)

{

String fileName = (new StringBuilder()).append(extractedFilePrefix).append(secondaryNumber).append(".zip").toString();

File extractedFile = new File(dexDir, fileName);

if (extractedFile.isFile())

{

files.add(extractedFile);

if (!verifyZipFile(extractedFile))

{

Log.i("MultiDex", (new StringBuilder()).append("Invalid zip file: ").append(extractedFile).toString());

throw new IOException("Invalid ZIP file.");

}

} else

{

throw new IOException((new StringBuilder()).append("Missing extracted secondary dex file '").append(extractedFile.getPath()).append("'").toString());

}

}

return files;

}

private static boolean isModified(Context context, File archive, long currentCrc)

{

SharedPreferences prefs = getMultiDexPreferences(context);

return prefs.getLong("timestamp", -1L) != getTimeStamp(archive) || prefs.getLong("crc", -1L) != currentCrc;

}

private static long getTimeStamp(File archive)

{

long timeStamp = archive.lastModified();

if (timeStamp == -1L)

timeStamp--;

return timeStamp;

}

private static long getZipCrc(File archive)

throws IOException

{

long computedValue = ZipUtil.getZipCrc(archive);

if (computedValue == -1L)

computedValue--;

return computedValue;

}

private static List performExtractions(File sourceApk, File dexDir)

throws IOException

{

String extractedFilePrefix;

List files;

ZipFile apk;

extractedFilePrefix = (new StringBuilder()).append(sourceApk.getName()).append(".classes").toString();

prepareDexDir(dexDir, extractedFilePrefix);

files = new ArrayList();

apk = new ZipFile(sourceApk);

int secondaryNumber = 2;

for (ZipEntry dexFile = apk.getEntry((new StringBuilder()).append("classes").append(secondaryNumber).append(".dex").toString()); dexFile != null; dexFile = apk.getEntry((new StringBuilder()).append("classes").append(secondaryNumber).append(".dex").toString()))

{

String fileName = (new StringBuilder()).append(extractedFilePrefix).append(secondaryNumber).append(".zip").toString();

File extractedFile = new File(dexDir, fileName);

files.add(extractedFile);

Log.i("MultiDex", (new StringBuilder()).append("Extraction is needed for file ").append(extractedFile).toString());

int numAttempts = 0;

boolean isExtractionSuccessful = false;

do

{

if (numAttempts >= 3 || isExtractionSuccessful)

break;

numAttempts++;

extract(apk, dexFile, extractedFile, extractedFilePrefix);

isExtractionSuccessful = verifyZipFile(extractedFile);

Log.i("MultiDex", (new StringBuilder()).append("Extraction ").append(isExtractionSuccessful ? "success" : "failed").append(" - length ").append(extractedFile.getAbsolutePath()).append(": ").append(extractedFile.length()).toString());

if (!isExtractionSuccessful)

{

extractedFile.delete();

if (extractedFile.exists())

Log.w("MultiDex", (new StringBuilder()).append("Failed to delete corrupted secondary dex '").append(extractedFile.getPath()).append("'").toString());

}

} while (true);

if (!isExtractionSuccessful)

throw new IOException((new StringBuilder()).append("Could not create zip file ").append(extractedFile.getAbsolutePath()).append(" for secondary dex (").append(secondaryNumber).append(")").toString());

secondaryNumber++;

}

try

{

apk.close();

}

catch (IOException e)

{

Log.w("MultiDex", "Failed to close resource", e);

}

break MISSING_BLOCK_LABEL_451;

Exception exception;

exception;

try

{

apk.close();

}

catch (IOException e)

{

Log.w("MultiDex", "Failed to close resource", e);

}

throw exception;

return files;

}

private static void putStoredApkInfo(Context context, long timeStamp, long crc, int totalDexNumber)

{

SharedPreferences prefs = getMultiDexPreferences(context);

android.content.SharedPreferences.Editor edit = prefs.edit();

edit.putLong("timestamp", timeStamp);

edit.putLong("crc", crc);

edit.putInt("dex.number", totalDexNumber);

apply(edit);

}

private static SharedPreferences getMultiDexPreferences(Context context)

{

return context.getSharedPreferences("multidex.version", android.os.Build.VERSION.SDK_INT >= 11 ? 4 : 0);

}

private static void prepareDexDir(File dexDir, String extractedFilePrefix)

throws IOException

{

File cache = dexDir.getParentFile();

mkdirChecked(cache);

mkdirChecked(dexDir);

FileFilter filter = new FileFilter(extractedFilePrefix) {

final String val$extractedFilePrefix;

public boolean accept(File pathname)

{

return !pathname.getName().startsWith(extractedFilePrefix);

}

{

extractedFilePrefix = s;

super();

}

};

File files[] = dexDir.listFiles(filter);

if (files == null)

{

Log.w("MultiDex", (new StringBuilder()).append("Failed to list secondary dex dir content (").append(dexDir.getPath()).append(").").toString());

return;

}

File arr$[] = files;

int len$ = arr$.length;

for (int i$ = 0; i$ < len$; i$++)

{

File oldFile = arr$[i$];

Log.i("MultiDex", (new StringBuilder()).append("Trying to delete old file ").append(oldFile.getPath()).append(" of size ").append(oldFile.length()).toString());

if (!oldFile.delete())

Log.w("MultiDex", (new StringBuilder()).append("Failed to delete old file ").append(oldFile.getPath()).toString());

else

Log.i("MultiDex", (new StringBuilder()).append("Deleted old file ").append(oldFile.getPath()).toString());

}

}

private static void mkdirChecked(File dir)

throws IOException

{

dir.mkdir();

if (!dir.isDirectory())

{

File parent = dir.getParentFile();

if (parent == null)

Log.e("MultiDex", (new StringBuilder()).append("Failed to create dir ").append(dir.getPath()).append(". Parent file is null.").toString());

else

Log.e("MultiDex", (new StringBuilder()).append("Failed to create dir ").append(dir.getPath()).append(". parent file is a dir ").append(parent.isDirectory()).append(", a file ").append(parent.isFile()).append(", exists ").append(parent.exists()).append(", readable ").append(parent.canRead()).append(", writable ").append(parent.canWrite()).toString());

throw new IOException((new StringBuilder()).append("Failed to create cache directory ").append(dir.getPath()).toString());

} else

{

return;

}

}

private static void extract(ZipFile apk, ZipEntry dexFile, File extractTo, String extractedFilePrefix)

throws IOException, FileNotFoundException

{

InputStream in;

ZipOutputStream out;

File tmp;

in = apk.getInputStream(dexFile);

out = null;

tmp = File.createTempFile(extractedFilePrefix, ".zip", extractTo.getParentFile());

Log.i("MultiDex", (new StringBuilder()).append("Extracting ").append(tmp.getPath()).toString());

out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(tmp)));

ZipEntry classesDex = new ZipEntry("classes.dex");

classesDex.setTime(dexFile.getTime());

out.putNextEntry(classesDex);

byte buffer[] = new byte[16384];

for (int length = in.read(buffer); length != -1; length = in.read(buffer))

out.write(buffer, 0, length);

out.closeEntry();

out.close();

break MISSING_BLOCK_LABEL_170;

Exception exception;

exception;

out.close();

throw exception;

Log.i("MultiDex", (new StringBuilder()).append("Renaming to ").append(extractTo.getPath()).toString());

if (!tmp.renameTo(extractTo))

throw new IOException((new StringBuilder()).append("Failed to rename \"").append(tmp.getAbsolutePath()).append("\" to \"").append(extractTo.getAbsolutePath()).append("\"").toString());

closeQuietly(in);

tmp.delete();

break MISSING_BLOCK_LABEL_285;

Exception exception1;

exception1;

closeQuietly(in);

tmp.delete();

throw exception1;

}

static boolean verifyZipFile(File file)

{

ZipFile zipFile = new ZipFile(file);

zipFile.close();

return true;

IOException e;

e;

Log.w("MultiDex", (new StringBuilder()).append("Failed to close zip file: ").append(file.getAbsolutePath()).toString());

break MISSING_BLOCK_LABEL_115;

ZipException ex;

ex;

Log.w("MultiDex", (new StringBuilder()).append("File ").append(file.getAbsolutePath()).append(" is not a valid zip file.").toString(), ex);

break MISSING_BLOCK_LABEL_115;

ex;

Log.w("MultiDex", (new StringBuilder()).append("Got an IOException trying to open zip file: ").append(file.getAbsolutePath()).toString(), ex);

return false;

}

private static void closeQuietly(Closeable closeable)

{

try

{

closeable.close();

}

catch (IOException e)

{

Log.w("MultiDex", "Failed to close resource", e);

}

}

private static void apply(android.content.SharedPreferences.Editor editor)

{

if (sApplyMethod != null)

try

{

sApplyMethod.invoke(editor, new Object[0]);

return;

}

catch (InvocationTargetException unused) { }

catch (IllegalAccessException unused) { }

editor.commit();

}

static

{

try

{

Class cls = android/content/SharedPreferences$Editor;

sApplyMethod = cls.getMethod("apply", new Class[0]);

}

catch (NoSuchMethodException unused)

{

sApplyMethod = null;

}

}

}

//MultiDex.java

package android.support.multidex;

import android.content.Context;

import android.content.pm.ApplicationInfo;

import android.content.pm.PackageManager;

import android.os.Build;

import android.util.Log;

import dalvik.system.DexFile;

import java.io.File;

import java.io.IOException;

import java.lang.reflect.*;

import java.util.*;

import java.util.regex.Matcher;

import java.util.regex.Pattern;

import java.util.zip.ZipFile;

// Referenced classes of package android.support.multidex:

//MultiDexExtractor

public final class MultiDex

{

private static final class V4

{

private static void install(ClassLoader loader, List additionalClassPathEntries)

throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, IOException

{

int extraSize = additionalClassPathEntries.size();

Field pathField = MultiDex.findField(loader, "path");

StringBuilder path = new StringBuilder((String)pathField.get(loader));

String extraPaths[] = new String[extraSize];

File extraFiles[] = new File[extraSize];

ZipFile extraZips[] = new ZipFile[extraSize];

DexFile extraDexs[] = new DexFile[extraSize];

for (ListIterator iterator = additionalClassPathEntries.listIterator(); iterator.hasNext();)

{

File additionalEntry = (File)iterator.next();

String entryPath = additionalEntry.getAbsolutePath();

path.append(':').append(entryPath);

int index = iterator.previousIndex();

extraPaths[index] = entryPath;

extraFiles[index] = additionalEntry;

extraZips[index] = new ZipFile(additionalEntry);

extraDexs[index] = DexFile.loadDex(entryPath, (new StringBuilder()).append(entryPath).append(".dex").toString(), 0);

}

pathField.set(loader, path.toString());

MultiDex.expandFieldArray(loader, "mPaths", extraPaths);

MultiDex.expandFieldArray(loader, "mFiles", extraFiles);

MultiDex.expandFieldArray(loader, "mZips", extraZips);

MultiDex.expandFieldArray(loader, "mDexs", extraDexs);

}

private V4()

{

}

}

private static final class V14

{

private static void install(ClassLoader loader, List additionalClassPathEntries, File optimizedDirectory)

throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException

{

Field pathListField = MultiDex.findField(loader, "pathList");

Object dexPathList = pathListField.get(loader);

MultiDex.expandFieldArray(dexPathList, "dexElements", makeDexElements(dexPathList, new ArrayList(additionalClassPathEntries), optimizedDirectory));

}

private static Object[] makeDexElements(Object dexPathList, ArrayList files, File optimizedDirectory)

throws IllegalAccessException, InvocationTargetException, NoSuchMethodException

{

Method makeDexElements = MultiDex.findMethod(dexPathList, "makeDexElements", new Class[] {

java/util/ArrayList, java/io/File

});

return (Object[])(Object[])makeDexElements.invoke(dexPathList, new Object[] {

files, optimizedDirectory

});

}

private V14()

{

}

}

private static final class V19

{

private static void install(ClassLoader loader, List additionalClassPathEntries, File optimizedDirectory)

throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException

{

Field pathListField = MultiDex.findField(loader, "pathList");

Object dexPathList = pathListField.get(loader);

ArrayList suppressedExceptions = new ArrayList();

MultiDex.expandFieldArray(dexPathList, "dexElements", makeDexElements(dexPathList, new ArrayList(additionalClassPathEntries), optimizedDirectory, suppressedExceptions));

if (suppressedExceptions.size() > 0)

{

IOException e;

for (Iterator i$ = suppressedExceptions.iterator(); i$.hasNext(); Log.w("MultiDex", "Exception in makeDexElement", e))

e = (IOException)i$.next();

Field suppressedExceptionsField = MultiDex.findField(loader, "dexElementsSuppressedExceptions");

IOException dexElementsSuppressedExceptions[] = (IOException[])(IOException[])suppressedExceptionsField.get(loader);

if (dexElementsSuppressedExceptions == null)

{

dexElementsSuppressedExceptions = (IOException[])suppressedExceptions.toArray(new IOException[suppressedExceptions.size()]);

} else

{

IOException combined[] = new IOException[suppressedExceptions.size() + dexElementsSuppressedExceptions.length];

suppressedExceptions.toArray(combined);

System.arraycopy(dexElementsSuppressedExceptions, 0, combined, suppressedExceptions.size(), dexElementsSuppressedExceptions.length);

dexElementsSuppressedExceptions = combined;

}

suppressedExceptionsField.set(loader, dexElementsSuppressedExceptions);

}

}

private static Object[] makeDexElements(Object dexPathList, ArrayList files, File optimizedDirectory, ArrayList suppressedExceptions)

throws IllegalAccessException, InvocationTargetException, NoSuchMethodException

{

Method makeDexElements = MultiDex.findMethod(dexPathList, "makeDexElements", new Class[] {

java/util/ArrayList, java/io/File, java/util/ArrayList

});

return (Object[])(Object[])makeDexElements.invoke(dexPathList, new Object[] {

files, optimizedDirectory, suppressedExceptions

});

}

private V19()

{

}

}

static final String TAG = "MultiDex";

private static final String OLD_SECONDARY_FOLDER_NAME = "secondary-dexes";

private static final String SECONDARY_FOLDER_NAME;

private static final int MAX_SUPPORTED_SDK_VERSION = 20;

private static final int MIN_SDK_VERSION = 4;

private static final int VM_WITH_MULTIDEX_VERSION_MAJOR = 2;

private static final int VM_WITH_MULTIDEX_VERSION_MINOR = 1;

private static final Set installedApk = new HashSet();

private static final boolean IS_VM_MULTIDEX_CAPABLE = isVMMultidexCapable(System.getProperty("java.vm.version"));

private MultiDex()

{

}

public static void install(Context context)

{

Log.i("MultiDex", "install");

if (IS_VM_MULTIDEX_CAPABLE)

{

Log.i("MultiDex", "VM has multidex support, MultiDex support library is disabled.");

return;

}

if (android.os.Build.VERSION.SDK_INT < 4)

throw new RuntimeException((new StringBuilder()).append("Multi dex installation failed. SDK ").append(android.os.Build.VERSION.SDK_INT).append(" is unsupported. Min SDK version is ").append(4).append(".").toString());

ApplicationInfo applicationInfo;

String apkPath;

ClassLoader loader;

RuntimeException e;

Throwable t;

File dexDir;

List files;

try

{

applicationInfo = getApplicationInfo(context);

if (applicationInfo == null)

return;

}

catch (Exception e)

{

Log.e("MultiDex", "Multidex installation failure", e);

throw new RuntimeException((new StringBuilder()).append("Multi dex installation failed (").append(e.getMessage()).append(").").toString());

}

label0:

{

synchronized (installedApk)

{

apkPath = applicationInfo.sourceDir;

if (!installedApk.contains(apkPath))

break label0;

}

return;

}

installedApk.add(apkPath);

if (android.os.Build.VERSION.SDK_INT > 20)

Log.w("MultiDex", (new StringBuilder()).append("MultiDex is not guaranteed to work in SDK version ").append(android.os.Build.VERSION.SDK_INT).append(": SDK version higher than ").append(20).append(" should be backed by ").append("runtime with built-in multidex capabilty but it's not the ").append("case here: java.vm.version=\"").append(System.getProperty("java.vm.version")).append("\"").toString());

try

{

loader = context.getClassLoader();

break MISSING_BLOCK_LABEL_216;

}

// Misplaced declaration of an exception variable

catch (RuntimeException e)

{

Log.w("MultiDex", "Failure while trying to obtain Context class loader. Must be running in test mode. Skip patching.", e);

}

set;

JVM INSTR monitorexit ;

return;

if (loader != null)

break MISSING_BLOCK_LABEL_232;

Log.e("MultiDex", "Context class loader is null. Must be running in test mode. Skip patching.");

set;

JVM INSTR monitorexit ;

return;

try

{

clearOldDexDir(context);

}

// Misplaced declaration of an exception variable

catch (Throwable t)

{

Log.w("MultiDex", "Something went wrong when trying to clear old MultiDex extraction, continuing without cleaning.", t);

}

dexDir = new File(applicationInfo.dataDir, SECONDARY_FOLDER_NAME);

files = MultiDexExtractor.load(context, applicationInfo, dexDir, false);

if (checkValidZipFiles(files))

{

installSecondaryDexes(loader, dexDir, files);

} else

{

Log.w("MultiDex", "Files were not valid zip files. Forcing a reload.");

files = MultiDexExtractor.load(context, applicationInfo, dexDir, true);

if (checkValidZipFiles(files))

installSecondaryDexes(loader, dexDir, files);

else

throw new RuntimeException("Zip files were not valid.");

}

set;

JVM INSTR monitorexit ;

goto _L1

exception;

throw exception;

_L1:

Log.i("MultiDex", "install done");

return;

}

private static ApplicationInfo getApplicationInfo(Context context)

throws android.content.pm.PackageManager.NameNotFoundException

{

PackageManager pm;

String packageName;

try

{

pm = context.getPackageManager();

packageName = context.getPackageName();

}

catch (RuntimeException e)

{

Log.w("MultiDex", "Failure while trying to obtain ApplicationInfo from Context. Must be running in test mode. Skip patching.", e);

return null;

}

if (pm == null || packageName == null)

{

return null;

} else

{

ApplicationInfo applicationInfo = pm.getApplicationInfo(packageName, 128);

return applicationInfo;

}

}

static boolean isVMMultidexCapable(String versionString)

{

boolean isMultidexCapable = false;

if (versionString != null)

{

Matcher matcher = Pattern.compile("(\\d+)\\.(\\d+)(\\.\\d+)?").matcher(versionString);

if (matcher.matches())

try

{

int major = Integer.parseInt(matcher.group(1));

int minor = Integer.parseInt(matcher.group(2));

isMultidexCapable = major > 2 || major == 2 && minor >= 1;

}

catch (NumberFormatException e) { }

}

Log.i("MultiDex", (new StringBuilder()).append("VM with version ").append(versionString).append(isMultidexCapable ? " has multidex support" : " does not have multidex support").toString());

return isMultidexCapable;

}

private static void installSecondaryDexes(ClassLoader loader, File dexDir, List files)

throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException, IOException

{

if (!files.isEmpty())

if (android.os.Build.VERSION.SDK_INT >= 19)

V19.install(loader, files, dexDir);

else

if (android.os.Build.VERSION.SDK_INT >= 14)

V14.install(loader, files, dexDir);

else

V4.install(loader, files);

}

private static boolean checkValidZipFiles(List files)

{

for (Iterator i$ = files.iterator(); i$.hasNext();)

{

File file = (File)i$.next();

if (!MultiDexExtractor.verifyZipFile(file))

return false;

}

return true;

}

private static Field findField(Object instance, String name)

throws NoSuchFieldException

{

Class clazz = instance.getClass();

_L2:

if (clazz == null)

break; /* Loop/switch isn't completed */

Field field;

field = clazz.getDeclaredField(name);

if (!field.isAccessible())

field.setAccessible(true);

return field;

NoSuchFieldException e;

e;

clazz = clazz.getSuperclass();

if (true) goto _L2; else goto _L1

_L1:

throw new NoSuchFieldException((new StringBuilder()).append("Field ").append(name).append(" not found in ").append(instance.getClass()).toString());

}

private static transient Method findMethod(Object instance, String name, Class parameterTypes[])

throws NoSuchMethodException

{

Class clazz = instance.getClass();

_L2:

if (clazz == null)

break; /* Loop/switch isn't completed */

Method method;

method = clazz.getDeclaredMethod(name, parameterTypes);

if (!method.isAccessible())

method.setAccessible(true);

return method;

NoSuchMethodException e;

e;

clazz = clazz.getSuperclass();

if (true) goto _L2; else goto _L1

_L1:

throw new NoSuchMethodException((new StringBuilder()).append("Method ").append(name).append(" with parameters ").append(Arrays.asList(parameterTypes)).append(" not found in ").append(instance.getClass()).toString());

}

private static void expandFieldArray(Object instance, String fieldName, Object extraElements[])

throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException

{

Field jlrField = findField(instance, fieldName);

Object original[] = (Object[])(Object[])jlrField.get(instance);

Object combined[] = (Object[])(Object[])Array.newInstance(((Object) (original)).getClass().getComponentType(), original.length + extraElements.length);

System.arraycopy(((Object) (original)), 0, ((Object) (combined)), 0, original.length);

System.arraycopy(((Object) (extraElements)), 0, ((Object) (combined)), original.length, extraElements.length);

jlrField.set(instance, ((Object) (combined)));

}

private static void clearOldDexDir(Context context)

throws Exception

{

File dexDir = new File(context.getFilesDir(), "secondary-dexes");

if (dexDir.isDirectory())

{

Log.i("MultiDex", (new StringBuilder()).append("Clearing old secondary dex dir (").append(dexDir.getPath()).append(").").toString());

File files[] = dexDir.listFiles();

if (files == null)

{

Log.w("MultiDex", (new StringBuilder()).append("Failed to list secondary dex dir content (").append(dexDir.getPath()).append(").").toString());

return;

}

File arr$[] = files;

int len$ = arr$.length;

for (int i$ = 0; i$ < len$; i$++)

{

File oldFile = arr$[i$];

Log.i("MultiDex", (new StringBuilder()).append("Trying to delete old file ").append(oldFile.getPath()).append(" of size ").append(oldFile.length()).toString());

if (!oldFile.delete())

Log.w("MultiDex", (new StringBuilder()).append("Failed to delete old file ").append(oldFile.getPath()).toString());

else

Log.i("MultiDex", (new StringBuilder()).append("Deleted old file ").append(oldFile.getPath()).toString());

}

if (!dexDir.delete())

Log.w("MultiDex", (new StringBuilder()).append("Failed to delete secondary dex dir ").append(dexDir.getPath()).toString());

else

Log.i("MultiDex", (new StringBuilder()).append("Deleted old secondary dex dir ").append(dexDir.getPath()).toString());

}

}

static

{

SECONDARY_FOLDER_NAME = (new StringBuilder()).append("code_cache").append(File.separator).append("secondary-dexes").toString();

}

}

//ZipUtil.java

package android.support.multidex;

import java.io.*;

import java.util.zip.CRC32;

import java.util.zip.ZipException;

final class ZipUtil

{

static class CentralDirectory

{

long offset;

long size;

CentralDirectory()

{

}

}

private static final int ENDHDR = 22;

private static final int ENDSIG = 0x6054b50;

private static final int BUFFER_SIZE = 16384;

ZipUtil()

{

}

static long getZipCrc(File apk)

throws IOException

{

RandomAccessFile raf = new RandomAccessFile(apk, "r");

long l;

CentralDirectory dir = findCentralDirectory(raf);

l = computeCrcOfCentralDir(raf, dir);

raf.close();

return l;

Exception exception;

exception;

raf.close();

throw exception;

}

static CentralDirectory findCentralDirectory(RandomAccessFile raf)

throws IOException, ZipException

{

long scanOffset = raf.length() - 22L;

if (scanOffset < 0L)

throw new ZipException((new StringBuilder()).append("File too short to be a zip file: ").append(raf.length()).toString());

long stopOffset = scanOffset - 0x10000L;

if (stopOffset < 0L)

stopOffset = 0L;

int endSig = Integer.reverseBytes(0x6054b50);

do

{

raf.seek(scanOffset);

if (raf.readInt() != endSig)

{

scanOffset--;

if (scanOffset < stopOffset)

throw new ZipException("End Of Central Directory signature not found");

} else

{

raf.skipBytes(2);

raf.skipBytes(2);

raf.skipBytes(2);

raf.skipBytes(2);

CentralDirectory dir = new CentralDirectory();

dir.size = (long)Integer.reverseBytes(raf.readInt()) & 0xffffffffL;

dir.offset = (long)Integer.reverseBytes(raf.readInt()) & 0xffffffffL;

return dir;

}

} while (true);

}

static long computeCrcOfCentralDir(RandomAccessFile raf, CentralDirectory dir)

throws IOException

{

CRC32 crc = new CRC32();

long stillToRead = dir.size;

raf.seek(dir.offset);

int length = (int)Math.min(16384L, stillToRead);

byte buffer[] = new byte[16384];

length = raf.read(buffer, 0, length);

do

{

if (length == -1)

break;

crc.update(buffer, 0, length);

stillToRead -= length;

if (stillToRead == 0L)

break;

length = (int)Math.min(16384L, stillToRead);

length = raf.read(buffer, 0, length);

} while (true);

return crc.getValue();

}

}

总共就四个类文件,至于dex的制作和需要主要的问题相信网上会有很多。自己的实践在这里做个简单的比较希望大神们莫笑。

版权声明:本文为博主原创文章,未经博主允许不得转载。

原文:http://blog.csdn.net/liu1164316159/article/details/47101185

com.android.support:multidex,Android 使用android-support-multidex解决Dex超出方法数的限制问题...相关推荐

  1. Android 使用android-support-multidex解决Dex超出方法数的限制问题,让你的应用不再爆棚

    时之沙: http://blog.csdn.net/t12x3456 随着应用不断迭代,业务线的扩展,应用越来越大(比如集成了各种第三方sdk或者公共支持的jar包,项目耦合性高,重复作用的类越来越多 ...

  2. 简述Android 解决65536/64K方法数限制方案

    在Android项目开发中,尤其是开发类似淘宝,京东,微信,直播等大型项目中,由于产品的迭代,业务模块的快速增长,到了一定的规模后难免会遇到65536/64K方法数的问题. 它是个什么鬼? 这个问题, ...

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

    ndroid-Easy-MultiDex 项目地址:TangXiaoLv/Android-Easy-MultiDex 简介:Android 傻瓜式 MultiDex 插件,从此再也不用担心方法数问题! ...

  4. android dex2oatd e,解決android項目Error:Execution failed for task ':app:dexDebug'.ebug'錯誤

    先上錯誤信息:Error:Execution failed for task ':app:dexDebug'.> com.android.ide.common.process.ProcessEx ...

  5. 由Android 65K方法数限制引发的思考

    前言 没想到,65536真的很小. 1 Unable to execute dex: method ID not in [0, 0xffff]: 65536 PS:本文只是纯探索一下这个65K的来源, ...

  6. Android:你好,androidX!再见,android.support

    190325 补充:莫名问题的解决 181106 补充:修改未迁移成功的三方库 1.AndroidX简介 点击查看Android文档中对androidx的简介 按照官方文档说明 androidx 是对 ...

  7. 【Android 应用开发】 Android 各种版本简介 ( Support 支持库版本 | Android Studio 版本 | Gradle 版本 | jcenter 库版本 )

    初学者遇到 Android Studio, 导入工程后, 会出现各种奇葩错误, 如果管理好各个插件, gradle, SDK, SDK Tools, 各种官方依赖库 的版本, 会将错误大大的减少; 这 ...

  8. Firefox Nightly 让 Android 机用上任意桌面端附加组件 | Expanded extension support in Firefox for Android Nightly

    Firefox Nightly 让 Android 机用上任意桌面端附加组件 官方文档:https://blog.mozilla.org/addons/2020/09/29/expanded-exte ...

  9. Android studio 实验过程中遇到的问题之android.support.v7.app.AppCompatActivity不能使用的解决办法

    android.support.v7.app.AppCompatActivity不能使用的解决办法 在构建项目时使用 android.support.v7.XX android.support.v4. ...

最新文章

  1. 串口上升时间标准_JESD204B 串行接口时钟需要及其实现
  2. Vue之vue-cli安装与简单调试
  3. 一文详解超参数调优方法
  4. 为什么说Prometheus是足以取代Zabbix的监控神器?
  5. php读取dxf,分享个DXF转G代码的实例
  6. 设置或者获取CheckboxList控件的选中值
  7. 修复RAID-5和镜像磁盘
  8. Android odex反编译为dex
  9. Linux 脚本获取当前路径父路径及常用命令
  10. c语言oj得pe,ACM入门之OJ~
  11. Linux文件加密方式gzip和bzip
  12. 运动会比赛计分系统c语言课程设计,c语言课程设计运动会比赛计分系统(含任务书).doc...
  13. 使用bat脚本创建快捷方式
  14. Linux内核UDP收包为什么效率低?能做什么优化?
  15. 计算机与人脑pdf_我们距离将人脑复制到计算机有多远
  16. 开箱即用的高匿代理抓取工具
  17. 说说python程序的执行过程_《师说》的“说”
  18. Redies实现持久化
  19. FPGA学习altera 系列 第十七篇 自动售货机设计
  20. Excel制作甘特图+自动报表

热门文章

  1. 2021年高压电工复审考试及高压电工模拟考试题库
  2. 使用 IDEA 创建 SpringBoot 项目时报错 Error parsing JSON response 解决方案【全】
  3. mysql临时表在工作中的使用
  4. SI战队人物专访-乔思远
  5. pytorch里面的Optimizer和optimizer.step()用法
  6. Vue · Vux:Tabbar导航
  7. 前端面试题整理(vue/js/css)
  8. html u蓝色下滑线,htmlu标签添加下划线的案例分析
  9. codemap~~~阅读源代码神器推荐
  10. 从Web后端(Java)转到游戏服务端的感受