上一篇主要介绍插件化的一些概念和作用,以及我为什么选择Small。现在来具体介绍下small。
Small的原理
1.动态加载class
Android类由DexClassLoader 加载,如果直接在编译搜索这个类的时候出现下面这种情况,我开始以为是没有关联源码,还折腾了好一会,后面发现,应该是特意搜不到了。不过开源直接在https://android.googlesource.com 搜。请自备梯子,我一般是用lantern+谷歌浏览器。
DexClassLoader的构造方法里面调用了父类的构造方法,我们跟进去可以看到BaseDexClassLoader 里面有个dexPath参数,这个通常是应用储存apk的目录/data/../*.apk。现在用来作为创建pathList。我们再看看new DexPathList里面做了什么。
DexPathList里面调用makeDexElements方法创建dexElements。我们跟进去看看做了什么。
可以看到,DexClassLoader不支持".so"后缀。那么small是怎么做的呢,看看伪代码。
为了让应用启动时能自动复制插件包到应用存储目录,需要支持".so"后缀。做法就是模拟压缩包加载代码块,创建一个dex元素,再反射添加到宿主class loader里的dexPathList。后面的演示过程中,你会看到small更新的所谓插件,就是编译过后的so文件。
2.动态加载resources
安卓资源由AssetManager加载。应用启动时,系统会为其创建一个AssetManager实例,并由addAssetPath方法添加资源搜索路径,默认添加:"/framework/base.apk" - Android base resources (base),"/data/app/*.apk" - The launching apk resources (host)
所有的资源需要通过一个唯一的id来访问,通常是形如0xPPTTNNNN,每个字段PPT的那个图有相应的介绍,我就不多说了。那么如何处理这个资源id分配的问题呢?有下面几种方案
但是这几种方案都有问题,为什么有问题的方案还会提?我是觉得这样可以养成一种思考的能力。第一种会导致插件之间不能访问资源。2.1字段有限,不好维护;2.2插件间无法访问资源;2.3修改aapt源码,不好维护。如果修改aapt生成产物,无缝连接,支持极致剪裁。资源包进行重新打包,重设资源id,small就是采取这种方式。具体深入的实现,这里就不提了。感兴趣的可以继续查看源码看看。
3.动态注册activities
每一个activity由Activity的startActivityForResult方法启动,通过instrumentation的execStartActivity方法激活生命周期。这个地方请大家留意下,后面也会提到这里。
在ActivityThread的performLaunchActivity方法中通过instrumentation的newActivity方法实例化。
如果要动态注册Activity,首先在宿主manifest中注册一个命名特殊的占坑activity来欺骗mInstrumentation.execStartActivity以获得生命周期,再欺骗mInstrumentation.newActivity来获得插件activity实例。Small封装一个instrumentation,来替换掉宿主。可以看到small里面的占坑。
写了这么多,,我都有点累了,相信此时看的你也一定有点累,但是知识岂有不付出就能得到的?加油吧!!大概就是这些,后面将介绍Small的使用,加载,启动,更新。实战开始!!APP项目如何与插件化无缝结合(三)
系列文章
APP项目如何与插件化无缝结合(一)
APP项目如何与插件化无缝结合(二)
APP项目如何与插件化无缝结合(三)
参考资料:
1.https://github.com/wequick/Small
2.http://www.tuicool.com/articles/NB32EjY
3.http://www.tuicool.com/articles/RR3QrmV
来自:http://www.jianshu.com/p/c0f3395dfa4e