简书链接:官方multidex的加载过程分析然后研究研究能否抄袭一点点技术
文章字数:557,阅读全文大约需要2分钟
1、检测jvm版本,正则 2.1.0 那么就是支持jvm,那么默认是不是进行dex的合并。
. doInstallation
方法获取到了ApplicationInfo
1 2 3 4 5
| mainContext: Context = {AppContext@4800} sourceApk: File = {File@4821} "/data/app/cn.qssq666.robot-2/base.apk" dataDir: File = {File@4822} "/data/user/0/cn.qssq666.robot" secondaryFolderName: String = {@4823} "secondary-dexes" prefsKeyPrefix: String = {@4824} ""
|
2、clearOldDexDir
第二步检查包名/files/secondary-dexes/是否存在存在则删除。里面所有文件,还把文件夹也删除了.
. /data/user/0/cn.qssq666.robot/code_cache/secondary-dexes
检查是否更改,更改就走另外一个方法否则走performExtractions
大概逻辑是读取apk的classdex 2-最终的dex全部打包(extract方法打包
)成zip文件
如先把classes2.dex解压打包成临时文件
/data/user/0/cn.qssq666.robot/code_cache/secondary-dexes/tmp-base.apk.classes238553433.zip
然后重命名为为/data/user/0/cn.qssq666.robot/code_cache/secondary-dexes/base.apk.classes2.zip
打包的代码分析
1 2 3 4 5 6 7 8 9 10 11 12 13
| InputStream in = apk.getInputStream(dexFile); ZipOutputStream out = null; File tmp = File.createTempFile("tmp-" + extractedFilePrefix, ".zip", extractTo.getParentFile()); Log.i("MultiDex", "Extracting " + tmp.getPath());
try { out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(tmp)));
try { ZipEntry classesDex = new ZipEntry("classes.dex"); classesDex.setTime(dexFile.getTime()); out.putNextEntry(classesDex); byte[] buffer
|
从zipentry实体获取entry的输入流然后创建一个ZipOutputStream
输出流,然后给他弄一个时间,然后zip的实体名字叫classes.dex
也就是每一个zip文件都有一个classes.dex
很显然,他的合并技术和我用的方法完全不同。是把一个包含多个dex的apk变成每一个apk,(当然这里叫zip)然后里面有一个classes.dex

最终的成果

然后
/data/user/0/cn.qssq666.robot/shared_prefs/multidex.version.xml
把时间戳和zip的crc校验码存起来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| private static void putStoredApkInfo(Context context, String keyPrefix, long timeStamp, long crc, List<MultiDexExtractor.ExtractedDex> extractedDexes) { SharedPreferences prefs = getMultiDexPreferences(context); Editor edit = prefs.edit(); edit.putLong(keyPrefix + "timestamp", timeStamp); edit.putLong(keyPrefix + "crc", crc); edit.putInt(keyPrefix + "dex.number", extractedDexes.size() + 1); int extractedDexId = 2;
for(Iterator var10 = extractedDexes.iterator(); var10.hasNext(); ++extractedDexId) { MultiDexExtractor.ExtractedDex dex = (MultiDexExtractor.ExtractedDex)var10.next(); edit.putLong(keyPrefix + "dex.crc." + extractedDexId, dex.crc); edit.putLong(keyPrefix + "dex.time." + extractedDexId, dex.lastModified()); }
edit.commit(); }
|
这才完成了
1 2
| List<? extends File> files = MultiDexExtractor.load(mainContext, sourceApk, dexDir, prefsKeyPrefix, false);
|
的逻辑
然后走
installSecondaryDexes(loader, dexDir, files);
具体逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| }
private static final class V19 { private V19() { }
private static void install(ClassLoader loader, List<? extends File> additionalClassPathEntries, File optimizedDirectory) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException { Field pathListField = MultiDex.findField(loader, "pathList"); Object dexPathList = pathListField.get(loader); ArrayList<IOException> suppressedExceptions = new ArrayList(); MultiDex.expandFieldArray(dexPathList, "dexElements", makeDexElements(dexPathList, new ArrayList(additionalClassPathEntries), optimizedDirectory, suppressedExceptions)); if (suppressedExceptions.size() > 0) { Iterator var6 = suppressedExceptions.iterator();
while(var6.hasNext()) { IOException e = (IOException)var6.next(); Log.w("MultiDex", "Exception in makeDexElement", e); }
Field suppressedExceptionsField = MultiDex.findField(dexPathList, "dexElementsSuppressedExceptions"); IOException[] dexElementsSuppressedExceptions = (IOException[])((IOException[])suppressedExceptionsField.get(dexPathList)); 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(dexPathList, dexElementsSuppressedExceptions); }
}
private static Object[] makeDexElements(Object dexPathList, ArrayList<File> files, File optimizedDirectory, ArrayList<IOException> suppressedExceptions) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { Method makeDexElements = MultiDex.findMethod(dexPathList, "makeDexElements", ArrayList.class, File.class, ArrayList.class); return (Object[])((Object[])makeDexElements.invoke(dexPathList, files, optimizedDirectory, suppressedExceptions)); } } }
|
很遗憾,这个v19的代码在我的23的手机并不能执行,
因为PathClassloader
没有makeDexElements
方法。
这里就不继续探索了,看看源码有哪几个把,copy过来改一下看看

首先要让IS_VM_MULTIDEX_CAPABLE
变成非常量,这样才好玩嘛。