目录
1.概述
- classloader基础
- 插件化
- replugin
- DynamicLoaderApk
2.classloader
2.1 java classloader
classloader是类加载器,描述将一个类的二进制流加载到虚拟机中的过程。
类的唯一性由它的类加载器和它本身来决定,也就是说一个class文件如歌使用不同的类加载器来加载,加载出来的类是不相等的。为了保证类的唯一性,使用双亲委派模型。
双亲委派模型:加载一个类会先委托给自己的父加载器去完成,父加载器会再向上委托,直到最顶层的类加载器,如父加载器没有找到要加载的类,子类才会尝试自己去加载,保证了加载的类都是一个类,例如object都是一个类。
防止系统级别类被篡改。
2.2 Android中的classloader
1)bootClassLoader
最顶层的classLoader,是所有classLoader的parent
2)pathClassLoader
继承自baseDexClassLoader,是apk的默认加载器,用来加载系统类和主dex文件中的类。系统类是BootClassLoader加载的
3)DexClassLoader
继承自baseDexClassLoader,用来加载外置的dex或者apk等
3.插件化
通过classloader动态加载插件apk和jar.
4.Replugin的原理
完整、稳定、占坑类的插件化方案,解耦,侵入性弱。
4.1 集成方式
- 宿主:
- gradle配置;
- application集成自RepluginApplication或者采用不继承的方式;
- 插件:
- gradle配置;
- 生成apk/jar-外置为apk,内置为jar,放在assets/plugins目录下。
4.2 加载过程
外置apk
- Replugin.install();
- Replugin.startActivity(context,Replugin.createIntent(插件名,类名));
- 支持卸载uninstall()
内置:不需要进行安装,启动方式同上,可通过install进行升级插件。
4.3 坑
为什么出现?Activity不在Androidmanifest中声明,就会出错。为了解决此问题,引入坑的概念。
方法:
- 在宿主中埋坑(gradle中配置);
- 宿主启动activity时,不去启动真正的activity,而是启动坑
- Androidmanifest检查通过
- Android系统创建activity的实例,Java反射原理
- classloader创建插件中的activity实例,返回给Android系统。
4.4 Replugin中的classLoader
1)RePluginClassLoader——代替宿主工作
继承自PathClassLoader,将原来的重要字段拷贝到本对象中,反射获取原class loader中的重要方法重写,最后重写loadclass方法。如果插件类中存在同名类,则使用插件中的类,没有再使用原来的类,
2)PluginDexClassLoader——加载插件apk类
找到查找的类,就返回。没有就会去宿主中查找。
4.5 Hook原理
Replugin通过hook住系统的PathClassloader并重写了loadClass方法来实现拦截类的加载过程,并且每一个插件apk都设置了一个pluginDexClassLoader,在类加载时,先使用pluginDexClassLoader去加载。
思想:是破坏了双亲委托模型
如何加载资源类?
4.3 原理——源码分析
Replugin的特点:
1.插件apk只需要进行相关的配置,代码的实现是不需要特殊定制的;
2.宿主需要配置相关的依赖,代码加载的时候,是把apk包作为jar包引入,并添加到asset目录中,包含资源文件。
3.页面跳转,需要写明全路径和包名信息,就可加载插件apk
源码解析:https://www.cnblogs.com/xinmengwuheng/p/7232395.html
https://blog.csdn.net/hellogmm/article/details/79056790
https://blog.csdn.net/degwei/article/details/79043165
5.DynamicLoaderApk
宿主apk+插件apk--1.动态加载库dl-apk.jar,仅参与编译;2.activity/service继承动态库,DLBasePluginActivity
5.1 加载过程
- 加载插件apk到内存中
- DLPluginManager.getInstance(this).loadApk(apkAllPath);
- 创建DexClassLoader,assetmanager,resources,保存到mPackHolders中,方便获得插件apk中的信息;
- 启动插件页面
- startPluginActivity(this,new DLIntent("包名",“类名”))
- 通过DexClassLoader类加载器生成对应的class对象,根据此class对象,获取它继承自的基础类,然后得到代理页面
- DLPluginImp实现了host代理和插件页面的类加载,通过attach接口进行关联。
5.2 缺点
- 侵入型强,插件类需继承自框架的基础类;
- 需要在AndroidManifest中进行代理类的声明(占坑)。