基于MuiltDex可以实现Hot Patch在不重新发布app的情况下,采用补丁的方式升级应用,用来快速解决一些线上的问题
google官方提供了MuiltDex的支持 compile 'com.android.support:multidex:1.0.0'
github地址:https://github.com/casidiablo/multidex
MuiltDex的基本原理是在打包的时候,将dex文件分拆成多个,并且在程序启动的时候动态加载,具体的使用方法可以参考 http://developer.android.com/intl/zh-cn/tools/building/multidex.html
下面是多dex加载的时序图:
1 public class MultiDexApplication extends Application {
2 @Override
3 protected void attachBaseContext(Context base) {
4 super.attachBaseContext(base);
5 MultiDex.install(this);
6 }
7 }
在使用MuiltDex的时候,需要继承MultiDexApplication
,可以看到在attachBaseContext
回调中,调用了MultiDex.install
,在android中Application、Activity、Service都是继承自Context的,在attachBaseContext之后,Context才创建完成,才能只用Context。
MultiDex.install
主要做了以下几个事情 * 检查虚拟机是否原生支持MultiDex,如果支持,支持返回:具体的判断是System.getProperty("java.vm.version").
通过虚拟机的版本号,大于2.1表示原生支持。 * SDK版本小于4,不支持,直接返回。 * SDK版本大于20,抛个警告 * 核心处理逻辑如下:通过MultiDexExtractor.load
获取FIles列表,通过installSecondaryDexes
处理获取的ClassLoader和Files
1 File dexDir = new File(applicationInfo.dataDir, SECONDARY_FOLDER_NAME);
2 List<File> files = MultiDexExtractor.load(context, applicationInfo, dexDir, false);
3 if (checkValidZipFiles(files)) {
4 installSecondaryDexes(loader, dexDir, files);
5 } else {
6 Log.w(TAG, "Files were not valid zip files. Forcing a reload.");
7 // Try again, but this time force a reload of the zip file.
8 files = MultiDexExtractor.load(context, applicationInfo, dexDir, true);
9
10 if (checkValidZipFiles(files)) {
11 installSecondaryDexes(loader, dexDir, files);
12 } else {
13 // Second time didn't work, give up
14 throw new RuntimeException("Zip files were not valid.");
15 }
16 }
MultiDexExtractor.load
的逻辑如下:
1)loadExistingExtractions:读取已经解压出来的文件
2)performExtractions:解压文件
1 static List<File> load(Context context, ApplicationInfo applicationInfo, File dexDir, boolean forceReload) throws IOException {
2 Log.i(TAG, "MultiDexExtractor.load(" + applicationInfo.sourceDir + ", " + forceReload + ")");
3 final File sourceApk = new File(applicationInfo.sourceDir);
4
5 long currentCrc = getZipCrc(sourceApk);
6
7 List<File> files;
8 if (!forceReload && !isModified(context, sourceApk, currentCrc)) {
9 try {
10 files = loadExistingExtractions(context, sourceApk, dexDir);
11 } catch (IOException ioe) {
12 Log.w(TAG, "Failed to reload existing extracted secondary dex files,"
13 + " falling back to fresh extraction", ioe);
14 files = performExtractions(sourceApk, dexDir);
15 putStoredApkInfo(context, getTimeStamp(sourceApk), currentCrc, files.size() + 1);
16
17 }
18 } else {
19 Log.i(TAG, "Detected that extraction must be performed.");
20 files = performExtractions(sourceApk, dexDir);
21 putStoredApkInfo(context, getTimeStamp(sourceApk), currentCrc, files.size() + 1);
22 }
23
24 Log.i(TAG, "load found " + files.size() + " secondary dex files");
25 return files;
26 }
installSecondaryDexes
的主要逻辑如下:主要是根据不同的sdk版本来处理,主要是通过反射来替换ClassLoader的path或者pathList
1 private static void installSecondaryDexes(ClassLoader loader, File dexDir, List<File> files) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException,IOException {
2 if (!files.isEmpty()) {
3 if (Build.VERSION.SDK_INT >= 19) {
4 V19.install(loader, files, dexDir);
5 } else if (Build.VERSION.SDK_INT >= 14) {
6 V14.install(loader, files, dexDir);
7 } else {
8 V4.install(loader, files);
9 }
10 }
11 }
文章评论
Clark’s numbers are pretty uninspiring considering his age and the leagues he played in. His PCL numbers, in particular, last year, are pretty meh for that le.e7gaWhat̵u;s the story with Schmidt? He’s already 26, and he’s never made it higher than High A. Seems like there’s got to be something to the story there, otherwise he looks like a really uninteresting prospect.
Thanks for shginra. What a pleasure to read!