首先,我们阐述为什么android需要插件化:
1:由于业务的增长,app的方法数逐渐达到65535(有人说用于检索方法数的列表大小使用short存储的,其实我看了源码之后并没有发现相关信息,并对此说法产生了怀疑,不过最后找到的结果就是,65535这个限制可能是由于dalvik的bytecode大小限制的,具体的可以查看官方文档)。
2:一个模块的变化都要整体编译一次app,维护成本太大了,用插件开发app会好很多
对于以上问题解决方案不少,著名的有h5,hybird,不过这些都没有native的体验好,于是之后又有react-native。不过本文不是阐述react-native,所以这里不加阐述。
国内也跟进,360推出了DroidPlugin*git*
我也开始学习他的这个项目,所以才有本文。也很感激网上有很多前辈已经贴出相关的文章,可供我参考借鉴
关于代理技术的话,熟悉spring的读者应该非常熟悉,spring利用动态代理实现AOP,极大的方便了开发
我们举个例子。如果,老板欠了我们的工资不发,我们是需要通过法律途径解决的,不过,我们大多数人应该不是自己去诉讼,而是请一位律师,这位律师就好比一个代理,帮助我们完成整个诉讼流程,我们自己只需在一旁只认老板罪行就行
我们定义一个接口,里面有各种诉讼流程
/**
* Created by chan on 16/4/10.
*/
public interface ILawsuit {
/**
* 提交诉讼
*/
void submit();
/**
* 举证
*/
void burden();
/**
* 辩护
*/
void defend();
/**
* 结束
*/
void finish();
}
我们的代表-小明,决定站起来做这个诉讼人
/**
* Created by chan on 16/4/10.
*/
public class XiaoMing implements ILawsuit {
@Override
public void submit() {
System.out.println("老板拖欠工资");
}
@Override
public void burden() {
System.out.print("合同书在这里,这是我的工资流水");
}
@Override
public void defend() {
System.out.println("证据都在这里 别BB");
}
@Override
public void finish() {
System.out.println("诉讼成功");
}
}
律师:
/**
* Created by chan on 16/4/10.
*/
public class Lawyer implements ILawsuit {
private ILawsuit m_iLawsuit;
public Lawyer(ILawsuit iLawsuit) {
m_iLawsuit = iLawsuit;
}
@Override
public void submit() {
System.out.println("拟仲裁材料");
m_iLawsuit.submit();
}
@Override
public void burden() {
System.out.println("指导委托人准备的材料");
m_iLawsuit.burden();
}
@Override
public void defend() {
System.out.println("争取到委托人辩护的机会");
//委托人开始辩护
m_iLawsuit.defend();
}
@Override
public void finish() {
System.out.println("交涉");
//显然证据确凿 肯定成功
m_iLawsuit.finish();
}
}
我们看到律师在委托人做具体事情之前,已经为其铺好垫,他只需简单的履行自己的职责,而无需关注外部环境发生了什么。
理解了代理是什么,我们开始真正的开始了
细想一下之前的例子,我们不难得出,在android里面如果我们需要Hook的话,这个hookd点要容易找到,小明毕竟是个具体的人,他是个代表嘛。自然我们hook时,应当针对单例的对象,或者静态的对象,因为他们只有一份,且相对不会发生改变。
好像有点抽象,我们还是举个例子吧。比如,我们现在要在每次启动一个activity之前都要打印一条信息。
最笨的方式就是用一个BaseActivity集成Activity,但是,如果我们这个项目已经进行了N多年,想象一下,这得修改多少源码,且这破坏了我们的设计原则,我们尽量扩展而不是修改代码。那些已有的代码都是经历时间考验的,修改之后可靠性会下降。
那么我们就HOOK吧。 先查看源码找一找线索
当我们启动一个Activity的时候,肯定都会调用startActivity**之类的代码
比如:
startActivity(intent);
我们切进去看下:
/**
* Same as {@link #startActivity(Intent, Bundle)} with no options
* specified.
*
* @param intent The intent to start.
*
* @throws android.content.ActivityNotFoundException
*
* @see {@link #startActivity(Intent, Bundle)}
* @see #startActivityForResult
*/
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
它调用了activity的 startActivity(Intent, Bundle)
再跟踪:
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
// Note we want to go through this call for compatibility with
// applications that may have overridden the method.
startActivityForResult(intent, -1);
}
}
又调用了startActivityForResult(Intent intent, int requestCode)
public void startActivityForResult(Intent intent, int requestCode) {
startActivityForResult(intent, requestCode, null);
}
又调用了startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options)
/**
* Launch an activity for which you would like a result when it finished.
* When this activity exits, your
* onActivityResult() method will be called with the given requestCode.
* Using a negative requestCode is the same as calling
* {
@li