插件化之旅3-Hook实现加载完整的apk

2019-08-27  本文已影响0人  Laughing_G

一、插件化与Hook实现集中式登录架构的区别?

不同点:目的不同,集中式登录框架是利用Hook实现的,插件化是实现加载一个未安装的apk;
相同点:都用到了Hook技术,都实现了可以加载没有在AndroidManifest.xml声明的Activity。

二、Hook插件化与插桩式插件化的不同点:

这一篇文章可以联系到插件化之旅1中的插桩式阿里框架,插桩是通过ProxyActivity重写了两个方法getResource和getClassLoader实现插件的加载。并用that实现上下文的传递。插桩式需要通过一个PluginManager去根据插件apk路径,加载classLoader,所以插桩式是需要宿主与插件之间有个中介桥梁的角色存在,而Hook技术实现插件化就没有这个中介桥梁的角色。并且宿主apk和插件apk已经完成了融合,是一家人的关系。

那么怎么样去融合插件apk呢?有两个问题:1.系统是如何加载class文件的?;2.系统是如何加载res资源文件的?

三、如何解决插件的class文件加载和插件res加载?

问题一:系统是如何加载Class文件的?
dalvik.system.PathClassLoader:加载已经安装的app的java文件。
这里不得不提到另外一个类DexClassLoader,它和PathClassLoader都是继承BaseClassLoader。
DexClassLoader能够加载任意路径的apk文件。这个给插件化提供了机会。
这里再讲个故事,小明想谈恋爱,但是没钱长的又丑,所以苦于找不到女朋友,但是小明有个好爸爸(老明),好爸爸情况也差不多,但是好爸爸有个好朋友(老王),老王直接问小明想要多大年龄的,小明说想要18岁的,此时老王手上没有18岁的资源,但是因为是老明的儿子,所以事情放在心上,所以老王从外地调来了一批18岁的资源,提供给小明来挑选。
PathClassLoader就相当于故事中没钱没势的小明,通过源码中查看PathClassLoader的loadClass方法,其实什么都没做,PathClassLoader本身也什么变量都没申明,他的loadclass调用的是父类BaseClassLoader.findClass方法(通过传入一个类名(className)就转换成一个Class类),findClass方法是调用了DexPathList类的findClass方法,这里的DexPathList就是拥有丰富资源的老王。查看DexPathList源码,她内部定义了Elements这个数组,这个Element粗俗的理解为一批18岁小妹妹的对象(Dex文件),Dex在Dailvk虚拟机中的内存映射是Element。
将到这里,我们是不是可以这样进行骚操作:相反设法的将插件的dex文件转换为Element数组,然后将这个插件的Element数组加入到宿主里面的Element数组。

所以问题一就找到了解决思路,那么接下来的问题又来了:怎么把插apk的dex转换成Element数组?

衍生问题:插件apk的dex转换为Element数组?
查看源码可以发现,DexClassLoader实例化(new)过程中,调用了super的构造方法,super是BaseClassLoader,继续查看BaseClassLoader的构造方法,可以惊喜的看到DexPathList被new出来了!!!所以你只要new出来DexClassLoader,那么系统就会自动的帮你把apk转换为Element数组,不过new的过程中需要传入apk的路径。

总的解决思路路线分为三步走:

image.png
image.png
image.png

问题2:如何解决插件res加载?
在解决问题2之前,先要明白两点:
1.Resource构建需要传入AssetManager;
2.string.xml/style.xml/color.xml/anim.xml等等这些在内存中的对象是StringBlock(这个在OPPO面试时候问到了这个问题,请注意!)。

在宿主的Application中,重写getAssetManager和getResource方法(暴露给插件的BaseActivity使用),根据插件apk路径,反射得到新的AssetManager和Resource。


image.png
image.png

总结:这篇文章核心点就是如何加载插件的class和res。

Demo地址:
https://github.com/cWX411904/HookPlugin

遗留问题:试想一下,如果宿主需要加载很多个插件,这种dex融合的方式会导致dexElements这个数组非常大,影响反应效率是一方面,也会引起内存爆棚的问题,那么怎么解决这个弊端呢?在下一篇“插件开发之旅4”会解决这个问题,大家敬请期待!

上一篇下一篇

猜你喜欢

热点阅读