赞
踩
1 什么是插件化?
插件化技术最初源于免安装运行 apk 的想法,这个免安装的 apk 就可以理解为插件,而支持插件的 app 我们一般叫宿主
2 插件化实现思路
1 如何加载插件的类?
2 如何加载插件的资源?
3 如何调用插件类?
Q 1, 回答问题之前我们要先了解什么是双亲委托机制
类在加载的过程中首先回去 判断当前类是否已经被加载过,如果没有加载过并且自己的父加载器不为空,将会让自己的父加载器去处理,父加载同样会去按照这个逻辑处理。如果没有找到父加载器,才会自己去加载。
这样处理的好处:
1、避免重复加载,当父加载器已经加载了该类的时候,就没有必要子ClassLoader再加载一次。
2、安全性考虑,防止核心API库被随意篡改。
在android中classLoader的继承关系如下
pathclassLoader 和DexClassLoader
在8.0(API 26)之前,它们二者的唯一区别是第二个参数 optimizedDirectory,这个参数的意思是生成的 odex(优化的dex)存放的路径。
在8.0(API 26)及之后,二者就完全一样了。
DexClassLoader中没有重写findClass 方法。而是使用父类BaseDexClassLoader中的,继续跟踪进去看,最终是通过Element类中的方法返回的,而每一个Element就是对应一个dex文件,因为一个apk中可能会存在多个dex,所以使用Element[]数组表示.
3 实现步骤
1. 创建插件的 DexClassLoader 类加载器,然后通过反射获取插件的 dexElements 值。
2. 获取宿主的 PathClassLoader 类加载器,然后通过反射获取宿主的 dexElements 值。
3. 合并宿主的 dexElements 与 插件的 dexElements,生成新的 Element[] 。
4. 最后通过反射将新的 Element[] 赋值给宿主的 dexElements 。
上面的操作可以让普通的类被加载执行,但是Activity呢?
我们知道activity 是需要在注册文件中添加的,如果没有添加会报错的,所以我们得解决这个问题。
思路:通过hook系统源码,通过验证阶段,然后在真正进行跳转得地方,将插件中得activity进行替换。将需要真正跳转的类藏在intent中,等通过验证再取出进行替换
/** * 插件化hook原理:intent.setClassName("插件包名","插件中的全类名"); * 1、hook AMS的startActivity方法, * 将intent改为 intent.setClassName("宿主包名","宿主中的全类名(代理类)"); * 2、当AMS过程执行结束,再将intent还原 * 将intent改为 intent.setClassName("插件包名","插件中的全类名"); * */
将真正跳转的类藏入intent
invoke函数内部找到startAcitivity方法,对其进行处理,替换内部的intent数据。
在 ActivityThread中的mH中,此时已经完成了验证,在mh中进行恢复
Q2 资源的文件该如何加载?
资源文件的加载离不开 Resources类,实际上,Resources 类也是通过 AssetManager 类来访问那些被编译过的应用程序资源文件的,不过在访问之前,它会先根据资源 ID 查找得到对应的资源文件名。 而 AssetManager 对象既可以通过文件名访问那些被编译过的,也可以访问没有被编译过的应用程序资源文件。
raw文件夹和assets文件夹有什么区别?
raw : Android会自动的为这目录中的所有资源文件生成一个ID,这意味着很容易就可以访问到这个资源,甚至在xml 中都是可以访问的,使用ID访问速度是最快的。
assets : 不会生成ID,只能通过AssetManager访问,xml中不能访问,访问速度会慢些,不过操作更加方便。
解题步骤:
1. 需要创建一个 Resources 对象,用来加载插件的资源
2. Resources 的创建需要 AssetManager 对象
3. AssetManager 创建的时候,需要指定资源路径
Q3 so文件该如何动态加载?
若要运用动态加载技术,编译前不把so文件放入jniLibs目录(原因很多,比如想减小安装包的大小),自然打包生成的安装包也不包含该so。接着在手机上安装这个apk并启动App,如果App的运行不涉及到jni方法的调用,那相安无事就当so不存在;如果App打开了某个页面,而该页面又需要调用jni方法,则App自动到指定地址下载需要的so文件,然后保存到用户目录,并从用户目录加载该so,最后再调用jni方法。
实现步骤:
步骤1、下载so
步骤2、拷贝so至私有(data)目录
步骤3、通过绝对路径加载so
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。