文章

插件化基础

插件化基础

插件化介绍

插件化背景

热修复是用来在线修复严重性的 bug,那么 Android Native 代码如何实现功能模块的在线更新?就需要用插件化了。插件化也是解决 64K 问题的一大利器。

出现的背景

  1. App 的体积越来越庞大,功能模块越来越多
  2. 模块耦合度高,协同开发沟通成本极大
  3. 方法数可能超过 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、插件中的类加载

v01nk

  • 如何自定义 ClassLoader 加载类文件
  • 如何调用插件 APK 文件中的类

二、资源加载

宿主中并没有插件中的资源,如何加载插件中的资源?
资源加载原理基本都是用 AssetManager 的隐藏方法 addAssetPath;但是,不同插件的资源如何管理?公用一套资源还是插件独立资源?共用资源如何避免资源冲突?对于资源加载,有的方案共用一套资源并采用资源分段机制解决冲突(要么修改 aapt 要么添加编译插件);有的方案选择独立资源,不同插件管理自己的资源。

1. Manifest 清单文件处理

tj2x9

宿主的 Manifest、依赖库 aar 的 Manifest 和插件 Apk 的 Manifest
这个就需要修改 gradle 打包流程,将插件的 Manifest 合并到宿主 Apk 的 Manifest 中去

三、四大组件生命周期管理

1、Activity 生命周期管理

  • 反射
    通过发射去获取 Activity 的各种生命周期方法(如 onCreate、onStart、onResume 等),然后在代理 Activity 中去调用插件 Activity 对应的生命周期即可。
  • 接口
    将 Activity 的生命周期方法提取出来作为一个接口,然后通过代理 Activity 去调用插件 Activity 的生命周期方法。

插件化实现方式

代理 Activity 方式实现插件化

插件化需要解决的问题?

  1. 插件 App 中的上下文
  2. 插件 App 的资源管理
  3. 插件 App 的生命周期管理 (最复杂)

1、插件 App 中的上下文?

由宿主 App 传递过来

2、插件 App 的资源管理

在宿主 App 中定义一个插桩 ProxyActivity,
在宿主 App 中启动插件 App 时,通过插件管理 ProxyManager,将 Resource 和 ClassLoader 路径替换成插件 App 的路径,
都交由 ProxyActivity 来加载,在 ProxyActivity 的 startActivity 中,通过 Bundle 将插件 App 的 Activity 信息塞进去,
在 ProxyActivity 的 onCreate 中,

本文由作者按照 CC BY 4.0 进行授权