0%

04-插件化-第一节

一、什么是插件化

插件化解决的问题:

  • App 体积越来越大,因为功能越来越多,如果App太大,用户都不想下载了

  • 模块之间的耦合度搞,协同开发的成本高了

  • 规避方法数超过 65535 问题,不过可以用 MutiApplication 了

  • 可以用于ABTest,某些用户下载插件A版本,某些下载插件B版本

  • 换肤,多开技术等都可以

选择开源框架的时候,根据自身需求:

  • 如果加载的插件不需要和宿主有任何耦合,也无需和宿主进行通信,那么推荐使用 RePlugin

  • 其他情况推荐 VirtualApk

插件化和组件化的区别?能用插件化的情况下不用组件化,组件化做不到按需下载,代码一起再 App 里面。可以做到各个插件的单独升级和下载。

二、插件化前置知识

插件化我们需要解决的问题:

  • 如何加载插件中的类

  • 如何启动四大组件,因为有生命周期

  • 如何加载插件中的资源

2.1 对于反射的了解

反射的思想:我们一个类,比如 Person 类,它的描述也是可以封装成一个 Class 对象,用于描述其成员变量、构造方法、方法等。

其中的属性,也是个对象 Field ,这个在反射中我们就能用到,所以我们可以构造出 Field 之后,对其进行 set 和 get 来设置和获取值,只不过,如果是静态属性,则get 的时候传入 null 即可,因为它是属于类级别;如果是成员属性,则需要传入这个类的对象,表示你要获取哪个对象的这个属性。

为什么反射耗时:

  • 产生临时对象,导致GC

  • 需要检查可见性,比较耗时

  • 字节码没有优化

  • 会做装箱、拆箱的操作,如 int 会变为 Integer

2.2 类加载器

使用反射的时候,forName 和 loadClass 会有什么区别?

  • forName 会进行类加载,验证、准备、解析,初始化;

  • loadClass 只会做类加载

澄清一下网上的错误说法,

关于classLoader的错误说法

其实 PathClassLoader 也是能加载未安装的 APK 的!老师在课程里面用代码验证了。

只是在 8.0 之前,DexClassLoader 构造函数在需要传入一个 odex 存放的位置,就这一个区别。在 8.0 之后基本上没有区别了。

PathClassLoader 和 BootClassLoader 有什么区别?

  • PathClassLoader 加载应用的类,比如你写的 MainActivity

  • BootClassLoader 加载 SDK 的类,比如 Activity 类,但是 AppcompactActivity 这种就是

ClassLoader 中 loadClass 方法加载类的步骤:

  • 首先 findLoadedClass 看看类是否已经加载过了,加载过了直接用

  • 其次让parent加载

  • 如果parent加载还没有,就自己 findClass 加载

整体的调用步骤如下图所示:

AndroidClassLoader加载类过程

BootClassLoader shi ClassLoader 的内部,它的 loadClass 只有 2 步, 首先 findLoadedClass , 如果没有直接就自己 find Class 了,因为它上面没有父 ClassLoader 。

为什么Android 要设计这样的双亲委派机制?基于2点:一是避免重复加载,父加载器已经加载的情况下,就不要加载了;二是安全性考虑,防止核心 API 被随意篡改

三、启动插件

通过对 ClassLoader 加载类的源码追踪,我们能看到如下的时序图:

Android加载Dex 的时序图

可以知道,最终是通过 DexPathList 去 findClass ,查看里面的源码可以知道:

  1. 一个 dex 文件对应一个 Element 对象

  2. 但是一个 Apk 可能有多个 dex 文件

  3. 所以使用 Element[] dexElements 数组存放app 中所有的 element

所以我们的思想步骤可以分为如下4 步:

  1. 获取宿主的 dexElements获取插件的 dexElements

  2. 获取插件的 newdexElements

  3. 合并 2 个 dexElements 得到新的 newdexElements

  4. newdexElements 赋值给宿主的 dexElements

谢谢你的鼓励