插件化基础
插件化介绍
插件化背景
热修复是用来在线修复严重性的 bug,那么 Android Native 代码如何实现功能模块的在线更新?就需要用插件化了。插件化也是解决 64K 问题的一大利器。
出现的背景
- App 的体积越来越庞大,功能模块越来越多
- 模块耦合度高,协同开发沟通成本极大
- 方法数可能超过 65535,占用内存过大
插件化概念
- 宿主
主 App,可以加载插件,也称为 Host - 插件
插件 App,被宿主加载的 APP,可以是跟普通 App 一样的 APK 文件 - 插件化
将一个应用按照宿主插件的方式改造就叫插件化
插件化核心技术
- Android ClassLoader 加载 class 文件原理
- Java 反射原理
- Android 资源加载原理
- 四大组件加载原理(四大组件加载流程,如何通过 ActivityManagerService 完成与系统通信)
插件化框架
- AndroidDynamicLoader
使用一个 Activity 作为外壳,动态加载一个未安装 apk 的 Fragment,并通过外壳 Activity 来处理 Fragment 的全部生命周期,达到动态加载一个 Android 视图界面的效果。
- dynamic-load-apk 框架(百度任玉刚)
创建一个静态的代理 Activity,将动态加载到未安装的 Activity 中的全部方法 (包括生命周期方法) 使用静态代理类调用执行,然后由于是动态加载的类,静态代理调用后没有办法拿到 super,只能在编写插件时使用 this 来代替 super,而这个 this 对象实际上就是静态代理类。
- android-pluginmgr
利用 Java 虚拟机字节码操作方式,通过动态生成一个插件类的子类,达到插件化的功能。
- Direct-Load-apk (lody)
通过找到一切 Activity 启动的根源:Instruction 通过替换这个类,来加载一个伪装的 Activity 欺骗系统的校验,而实际上加载的是未安装的插件
- DroidPlugin(360 手机助手)
通过修改 Instruction 实现 Activity 动态加载,通过修改 ActivityThread 和 ActivityManagerService 实现 Service 动态加载。
- DynamicAPK(携程)
实现了自己的 aapt,替换掉 SDK 中的 aapt 可以做到对插件资源的重排,达到资源通用
- iReader 的 ZeusPlugin
- Small(个人开发者林光亮,阿里音乐)
主要内容是在 groovy 脚本里面,通过脚本修改了编译后生成的插件资源 id
- alibaba 的 atlas
手机淘宝 - RePlugin
- VirtualAPK
插件化原理
插件化要解决的三个问题
一、ClassLoader 管理
类的加载可以使用 Java 的 ClassLoader 机制,但是对于 Android 来说,并不是说类加载进来就可以用了,很多组件都是有生命周期的;因此对于这些类,必须给它们注入活力,也就是所谓的组件生命周期管理;另外,如何管理加载进来的类也是一个问题,假设多个插件依赖了相同的类,是抽取公共依赖进行管理还是插件单独依赖?这就是 ClassLoader 的管理问题。
将不同插件的 ClassLoader 存储在一个 HashMap 中,可确保不同插件中的类彼此互不干扰。
1、插件中的类加载
- 如何自定义 ClassLoader 加载类文件
- 如何调用插件 APK 文件中的类
二、资源加载
宿主中并没有插件中的资源,如何加载插件中的资源?
资源加载原理基本都是用 AssetManager 的隐藏方法 addAssetPath;但是,不同插件的资源如何管理?公用一套资源还是插件独立资源?共用资源如何避免资源冲突?对于资源加载,有的方案共用一套资源并采用资源分段机制解决冲突(要么修改 aapt 要么添加编译插件);有的方案选择独立资源,不同插件管理自己的资源。
1. Manifest 清单文件处理
宿主的 Manifest、依赖库 aar 的 Manifest 和插件 Apk 的 Manifest
这个就需要修改 gradle 打包流程,将插件的 Manifest 合并到宿主 Apk 的 Manifest 中去
三、四大组件生命周期管理
1、Activity 生命周期管理
- 反射
通过发射去获取 Activity 的各种生命周期方法(如 onCreate、onStart、onResume 等),然后在代理 Activity 中去调用插件 Activity 对应的生命周期即可。 - 接口
将 Activity 的生命周期方法提取出来作为一个接口,然后通过代理 Activity 去调用插件 Activity 的生命周期方法。
插件化实现方式
代理 Activity 方式实现插件化
插件化需要解决的问题?
- 插件 App 中的上下文
- 插件 App 的资源管理
- 插件 App 的生命周期管理 (最复杂)
1、插件 App 中的上下文?
由宿主 App 传递过来
2、插件 App 的资源管理
在宿主 App 中定义一个插桩 ProxyActivity,
在宿主 App 中启动插件 App 时,通过插件管理 ProxyManager,将 Resource 和 ClassLoader 路径替换成插件 App 的路径,
都交由 ProxyActivity 来加载,在 ProxyActivity 的 startActivity 中,通过 Bundle 将插件 App 的 Activity 信息塞进去,
在 ProxyActivity 的 onCreate 中,