AndFix解析——(上)
来源:互联网 发布:壹方凌网络是干嘛的 编辑:程序博客网 时间:2024/06/03 16:13
阿里巴巴前一段时间开源了他们用来解决线上紧急bug的一款Android库——AndFix
对Android开发者来说真是一个很好的消息。
基于自己的经验,太长的文字很少有人可以一口气看下来的,所以我打算分成多篇来分析 这是这个库解析的第一篇,
我们先看一下其中的Demo代码,其中调用加载库的代码如下所示:
/** * sample application * * @author sanping.li@alipay.com * */public class MainApplication extends Application {private static final String TAG = "euler";private static final String APATCH_PATH = "/out.apatch";/** * patch manager */private PatchManager mPatchManager;@Overridepublic void onCreate() {super.onCreate();// initializemPatchManager = new PatchManager(this);mPatchManager.init("1.0");Log.d(TAG, "inited.");// load patchmPatchManager.loadPatch();Log.d(TAG, "apatch loaded.");// add patch at runtimetry {// .apatch file pathString patchFileString = Environment.getExternalStorageDirectory().getAbsolutePath() + APATCH_PATH;mPatchManager.addPatch(patchFileString);Log.d(TAG, "apatch:" + patchFileString + " added.");} catch (IOException e) {Log.e(TAG, "", e);}}}
可以看到代码中首先通过PatchManager的构造函数初始化了PatchManager
对象,
PatchManager构造函数
那么PatchManager
对象里面都有什么呢,我们深入其中了解一下。
public PatchManager(Context context) { this.mContext = context;this.mAndFixManager = new AndFixManager(this.mContext);this.mPatchDir = new File(this.mContext.getFilesDir(), "apatch");this.mPatchs = new ConcurrentSkipListSet();this.mLoaders = new ConcurrentHashMap();}
原来维持了一个Context对象的引用,初始化了AndFixManager对象,mPatchDir对象为存放Patch文件的文件夹,初始化了Patch的集合,还有持有ClassLoader的Map
其中一些内容的声明如下:
private final Context mContext;private final AndFixManager mAndFixManager;private final File mPatchDir;private final SortedSet<Patch> mPatchs;private final Map<String, ClassLoader> mLoaders;
我们对构造函数的分析在这里就结束了,我们先不深入的跟进Patch和AndFixManager这两个类了。
PatchManager init(String version)
接下来分析PatchManager
类中的init(String version)
函数, 先来看代码
public void init(String appVersion) {//如果mPatchDir不存在,则创建文件夹,如果创建失败,则打印Logif(!this.mPatchDir.exists() && !this.mPatchDir.mkdirs()) { Log.e("PatchManager", "patch dir create error."); } else if(!this.mPatchDir.isDirectory()) {//如果遇到同名的文件,则将该同名文件删除 this.mPatchDir.delete(); } else {//在该文件下放入一个名为_andfix_的SharedPreferences文件, SharedPreferences sp = this.mContext.getSharedPreferences("_andfix_", 0); String ver = sp.getString("version", (String)null); if(ver != null && ver.equalsIgnoreCase(appVersion)) { this.initPatchs(); } else { this.cleanPatch(); sp.edit().putString("version", appVersion).commit(); }}}
接下来我们分析上面代码中的如下代码
//如果从_andfix_这个文件获取的ver不是null,而且这个ver和外部初始化时传进来的版本号一致if(ver != null && ver.equalsIgnoreCase(appVersion)) {this.initPatchs();} else {this.cleanPatch();sp.edit().putString("version", appVersion).commit();}
先看else内的内容,else里执行力cleanPatch()
和把外部初始化的时候传进来的版本号放入SharedPreferences里。 cleanPatch()
做了什么操作呢,我们跟进去看一看
private void cleanPatch() {//获取mPatchDir目录下所有文件 File[] files = this.mPatchDir.listFiles(); File[] arr$ = files; int len$ = files.length; for(int i$ = 0; i$ < len$; ++i$) { File file = arr$[i$]; //将此文件从OptFile文件夹删除 this.mAndFixManager.removeOptFile(file); //这个方法的作用就是如果file是文件,则删除它,如果file是文件夹,则将它和它里面的文件都删除 if(!FileUtil.deleteFile(file)) { Log.e("PatchManager", file.getName() + " delete error."); } }}
如源码中的注释,就是删除了之前在那两个文件夹下的所有的补丁文件。
现在来分析一下this.initPatchs()
做了什么事
private void initPatchs() { File[] files = this.mPatchDir.listFiles(); File[] arr$ = files; int len$ = files.length; for(int i$ = 0; i$ < len$; ++i$) { File file = arr$[i$]; this.addPatch(file); }}
代码很简单,就是把mPatchDir文件夹下的文件作为参数传给了addPatch(File)
方法 那this.addPatch(file)
做了什么呢
//把扩展名为.apatch的文件传给Patch做参数,初始化对应的Patch,//并把刚初始化的Patch加入到我们之前看到的Patch集合mPatchs中private Patch addPatch(File file) { Patch patch = null; //扩展名是否为".apatch" if(file.getName().endsWith(".apatch")) { try { patch = new Patch(file); this.mPatchs.add(patch); } catch (IOException var4) { Log.e("PatchManager", "addPatch", var4); } } return patch;}
上面的代码很好理解,此时,我们已经完整的走下来了init(String version)
这个方法。 再次出现了Patch这个类,但是我们依然要把它放在一边,因为由于篇幅限制,第一篇不会分析这个类。
接下来,我们继续跟着demo走,会执行两个方法,一个mPatchManager.loadPatch()
,一个mPatchManager.addPatch(patchFileString)
, loadPatch()
方法是这个库执行替换的核心方法,我会在以后单独写一篇文章来分析,所以,在这篇文章的最后,我们跟进addPatch(String)
这个方法一看究竟
public void addPatch(String path) throws IOException { File src = new File(path); File dest = new File(this.mPatchDir, src.getName()); if(dest.exists()) { //在mPatchDir文件夹下存在该文件,则AndFixManager移除该文件 this.mAndFixManager.removeOptFile(dest); }//将文件从src复制到dest,只不过阿里用了NIO来复制文件 FileUtil.copyFile(src, dest); //调用了另外一个addPatch方法,以文件作为参数 Patch patch = this.addPatch(dest); if(patch != null) { //同样调用了loadPatch(Patch)方法 this.loadPatch(patch); }}
简单来说,上面的方法就是将补丁文件复制到/data/data/{包名}/apatch 目录内,如果在OptFile文件夹中存在,则删除。 然后调用另外一个addPatch(File)
方法,然后loadPatch()
下面,我们来看一下重载的addPatch(File)
方法
private Patch addPatch(File file) { Patch patch = null; if(file.getName().endsWith(".apatch")) { try { patch = new Patch(file); //把从file文件生成的patch加入到mPatchs这个Set中 this.mPatchs.add(patch); } catch (IOException var4) { Log.e("PatchManager", "addPatch", var4); } } return patch;}
该方法主要做的事情在注释中即可了解,到这里,第一篇分析就结束了。
原文地址: http://yunair.github.io/blog/2015/09/25/AndFix-%E8%A7%A3%E6%9E%90(%E4%B8%8A).html
- AndFix解析——(上)
- AndFix解析——(上)
- AndFix解析——(中)
- AndFix解析——(下)
- AndFix解析——(中)
- AndFix解析——(下)
- AndFix热修复 —— 实战与源码解析
- AndFix热修复 —— 实战与源码解析
- AndFix热修复 —— 实战与源码解析
- AndFix热修复 —— 实战与源码解析
- Android热修复学习之旅——Andfix框架完全解析
- Android热修复框架——AndFix
- Android热修复实践应用—AndFix
- Android热修复方案—AndFix
- AndFix原理以及源码解析
- andfix
- AndFix
- Android不发版也能在线修Bug?——AndFix 框架
- elasticsearch Windows安装
- Java中break、continue、return语句的使用区别对比(附实例)
- IOS 图片拉伸处理方法
- SVN过滤
- lzg_ad:XP Embedded SP2正式版安装详解
- AndFix解析——(上)
- C#实现压缩与解压缩
- ffmpeg命令行实现YUV和RGB之间格式的转换
- EXCEL表写入时问题解决
- Spring容器初始化后执行自定义的业务操作
- Android设备通过wifi连接adb调试
- HUSTM 1601 - Shepherd
- KMP算法
- 多线程下载