Android插件化-Activity替换

因为Activity的特殊性,activity的class被classLoader加载之后是可以当普通类使用了,但是生命周期需要系统回调。而且activity的启动过程比较复杂,不是一个简单的类加载和反射的过程。
为实现Activity的生命周期,实现方案都需要预先在宿主中占位,插件化技术发展到现在,为了轻量化,目前主流的实现方案有两种:

  1. 替换Class loader
  2. 替换Instrumentation

Activity启动过程

要实现这两种方案,先要了解Activity的启动过程

Activity_start.png
  • AMS: 即ActivityManagerServices,服务端对象,负责系统中所有Activity的生命周期
  • ActivityThread:App的入口,当开启App之后,会调用main()开始运行,开启消息循环队列。就是主线程。
    与ActivityManagerServices配合,一起完成Activity的管理工作。
  • Instrumentation: 应用内单实例对象,负责Activity的创建和暂停
  • ApplicationThread:负责ActivityManagerService与ActivityThread之间的交互。在ActivityManagerService需要管理相关Application中的Activity的生命周期时,通过ApplicationThread的代理对象与ActivityThread通讯
  • ApplicationThreadProxy: ApplicationThread在服务器端的代理,负责和客户端的ApplicationThread通讯。AMS就是通过该代理与ActivityThread进行通信的
  • ActivityStack:Activity在AMS的栈管理,用来记录已经启动的Activity的先后关系,状态信息等。通过ActivityStack决定是否需要启动新的进程

启动流程简述

  1. 先通过Instrumentation检查对应的Activity是否已经启动,若已经启动切符合条件则直接返回。没有在调用AMS去启动activity
  2. AMS调用ActivityStarter启动Activity。ActivityStarter先解析Intent中Activity的信息。查询系统中是否有符合要求的Activity
  3. 使用合适的ActivityStack和 launch flags 来启动 Activity, 如果存在可以直接恢复 Activity,则恢复,否则重新启动 Activity
  4. 如果此时Activity所在的App未启动,则先创建对应的App进程
  5. 若要启动新的Activity,AMS会通过binder调用App进程,使用 ActivityThread 去执行启动,
  6. Instrumentation对过反射生成Activity的实例
  7. 使用handler来调用新生成的Activity的生命周期

替换Class loader

实现过程

  1. 自定义一个PathClassLoader,App启动时将自定义的ClassLoader替换系统的ClassLoader
  2. 解析启动插件Activity的intent,找到插件中对应的Activity class
  3. 分配与要启动的Activity的启动方式一致的坑位Activity,并保持两个Activity的关联
  4. 让系统启动坑位的Activity, 系统会使用替换过的ClassLoader加载坑位的Activity
  5. 替换过的ClassLoader启动坑位的Activity时,通过对应的关联找到对应的插件中的activity,
    找到后加载并返回
  6. android系统拿到的Activity就是插件中的activity, 然后调用它的生命周期

替换Instrumentation

这个方案比较简单和轻量,由于activity的启动和反射都是在Instrumentation中进行的,所以只hook启动和反射生成实例的程就可以将占位的activity替换为插件中的Activity

实现过程

  1. 封装一个Instrumentation,重写启动Activity的方法
  2. 将启动的插件中的Activity替换为占位的activity
  3. 重写Instrumentation的newActivity方法,使用插件的class loader 反射生成插件的activity
  4. 然后将封装的Instrumentation替换掉宿主中的Instrumentation

这样宿主启动的acticity最终被替换成了插件中的activity,生命周期完全由系统管理。
但是由于启动方式多样性,所以占坑的时候需要埋入比较多的占坑Acttivity来应对不同的启动方式
这个方案的过程比较简单,而且hook的点很少,所以很轻量

你可能感兴趣的:(Android插件化-Activity替换)