从零开始学android([Android]从零开始学习VirtualApp)

从零开始学android

最近一直在研究拜读VirtualApp和VirtualXposed,学习完之后真是感慨颇多。asLody和weishu两位大神对源码理解之深,真是让人感到敬佩。lody一个高中生居然能写出如此优雅和精妙的代码,真是让我自叹不如。

VirtualApp原理虽然非常简单,但它设计的却很精妙,很多独特之处,比如简化反射的mirror,通过ContentProvider实现的IPCBus,完美的解决了Android-AIDL的繁琐,也为三组进程(服务进程,应用进程,UI进程)的通信提供了简单,有效的解决方式。以及H-Handler的处理,MethodInvocation的注入方式,等等…

出于种种考虑,作者已经商业化了,基本不再提供更新了。但是其开源的版本对于学习来说已经足够了,相信理解的人已经完全可以自己维护了。

从这篇文章开始,我会用自己的理解,把VirtualApp的原理尽量写清楚,包括weishu大神对xposed的封装,我也会讲一些。当然我的浅薄理解可能会有偏差,欢迎大家拍砖交流。RTFSC,接下来开始吧。

Mirror

VirtualApp的本质就是反射,动态代理,所以代码中的反射自然是必不可少。如何让反射更优雅,更可读呢?让我们来看看VirtualApp中反射的例子

声明好mirror类,如何使用呢?

无需任何初始化,即可直接使用。原理其实非常简单,先介绍下使用方式,之后再来解释一下如何封装的反射。
使用方法如下:
声明一个Mirror类,其中必须包含一个TYPE,用RefClass来映射mappingClass和targetClass
根据需要声明以下几种类型的变量
变量
RefBoolean
RefDouble
RefFloat
RefInt
RefLong
RefObject
RefStaticInt
RefStaticObjecg
方法
RefMethod
RefStaticMethod
如果是field,直接可以调用set,get进行设置,获取,如果是method,直接调用call
如果方法包含参数,可以使用注解MethodParams或者MethodReflectParams进行声明

实现原理:
当Class被类加载器加载时,会先初始化类的静态变量,所以实现的核心代码都在RefClass的load方法中,具体代码如下:

首先会从mappingClass中查找所有static修饰的变量,然后在REF_TYPES这种Mapping中找出映射的constructor。REF_TYPES的声明如下:

这样,load方法的功能也就清晰明了了。load的作用就是对mappingClass中的所有Static变量进行赋值,这也就是为什么我们无需初始化变量就可以直接使用的原因。接下来我们以RefMethod为例,来看一看如何封装的反射。我们先看一下RefMethod的构造函数:

从RefClass的代码可以得知,RefMethod的两个参数分别时realClass和mappingClass中的field。代码逻辑十分简单,从realClass中寻找和mappingClass中field同名的method。至此,我们已经寻找到了真正target的method了。为什么我要以RefMethod举例呢?因为有一点很有意思,如下图:

当RefMethod包含注解MethodParam时,并且当前的类加载器和注解中的类加载器相同时,它会尝试获取注解中类的TYPE变量,这也就是为什么我们声明的时候都要命名为TYPE的原因。(只有当MethodParam中的Type也是无法直接访问的Class的时候,才会走到此Case)
接下来就十分清晰了,当我们需要调用这个需要反射的method的时候,只需要直接调用call方法就可以了,具体实现如下:

这块就是Java的API了,没什么可说的了。自此,Mirror的逻辑已经说的很清楚了。Mirror本身非常简单,也很容易理解,但是不得不说asLody的思路还是很巧妙的。

感悟

Mirror非常简单,本来并不想来针对性的写,但是考虑到后续使用的非常普遍,而且在实际项目中也可以得到应用,所以就在开篇大体说了一些。    
Mirror也有一些场景没有覆盖。比如Class分布在不同的类加器中,RefClass在load时,无法为其设置指定的类加载器,导致ClassNotFound,后续我针对这块也做了相关改动。

再次感谢asLody和weishu两位大神的开源精神。

如有想法,欢迎交流。

从零开始学android相关文章

版权声明