插件化
2018-07-30 本文已影响6人
34sir
作用
- 宿主和插件分开编译 编译时只需要编译宿主 插件是在编译完成之后下发到宿主的
- 并发开发 宿主发布版本不受插件影响 只需要提供一个入口给插件
- 动态更新插件
- 按需下载模块
- 65536
与组件化的区别
- 组件化将app拆分成多个模块 开发过程中相互依赖或者单独调试 每个组件相当于一个lib
- 插件化也是拆分成很多模块 包括宿主和插件 每个插件都是一个apk
生命周期方案
- 接口回调控制生命周期
- 利用ActivityThread 和Instrumentation hook ProxyActivity
- 改变AMS PMS 源码
步骤
① PackageManager获取插件入口activity
② 构造dexclassloader更换ProxyActivity的classloader
③ 反射AssetManager 重新构造resources
难点
- 插件中 ClassLoader 的问题;
DexClassLoader可以加载jar/apk/dex 可以加载未安装的apk; PathClassLoader只能加载已经安装过的apk
替换宿主activity的classloader目的是 加载插件apk的class - 插件中的资源文件访问问题;
AssetManager实例并且反射调用addAssetPath方法 - 插件中 Activity 组件的生命周期问题;
封装一个instrumentation,替换掉宿主的 (InstrumentationWrapper) - .so 文件加载
- Service 插件化
small分析
为什么用到.so?
- so机制让开发者最大化利用已有的C和C++代码,达到重用的效果,利用软件世界积累了几十年的优秀代码
- so是二进制,没有解释编译的开消,用so实现的功能比纯java实现的功能要快
- so内存分配不受Dalivik/ART的单个应用限制,减少OOM
- 相对于java代码,二进制代码的反编译难度更大,一些核心代码可以考虑放在so中
通过buildLib和buildBundle来把非宿主的app中的文件打包为.so文件,我们最终安装到手机上的apk其实就是只有宿主的apk和其内部的.so文件,通过加载.so文件来实现加载插件中的文件
使用注意点
- 模块名形如:app., lib.或者web.* ; 包名包含:.app., .lib.或者.web. Small会根据包名对插件进行归类
- bundle.json 注册依赖模块
- 宿主moudle不能引入依赖模块(lib) 只能是插件模块引入依赖模块
- 列表内容更新:cleanLib->cleanBundle->buildLib(准备基础库)->buildBundle(打包所有组件)
- 各个插件模块的fragment命名一定要是MainFragment不然会出现空指针异常
- createObject前,需要再此页面之前已经存在activity
核心原理
- Android类由DexClassLoader加载
- 安卓资源由AssetManager加载 创建AssetManager实例并且反射调用addAssetPath方法添加资源搜索路径 ;为避免id冲突宿主以及各个插件之间的资源id需要分段处理,解决方案:重新打包,重新设置id
- 生命周期受Instrumentation监控 封装一个instrumentation,替换掉宿主的 (InstrumentationWrapper)
关于smallLibs
- 存放组件.so包
- 宿主运行时自动复制其下.so到缓存区
相关问题
- 对Service的支持
支持动态加载,不支持动态注册 - 插件和宿主必须在同一个进程
- 宿主和各个插件之间的资源可以互相访问 支持sf