Android全面插件化RePlugin流程与源码解析.docx

上传人:b****6 文档编号:15382168 上传时间:2023-07-04 格式:DOCX 页数:13 大小:122.95KB
下载 相关 举报
Android全面插件化RePlugin流程与源码解析.docx_第1页
第1页 / 共13页
Android全面插件化RePlugin流程与源码解析.docx_第2页
第2页 / 共13页
Android全面插件化RePlugin流程与源码解析.docx_第3页
第3页 / 共13页
Android全面插件化RePlugin流程与源码解析.docx_第4页
第4页 / 共13页
Android全面插件化RePlugin流程与源码解析.docx_第5页
第5页 / 共13页
Android全面插件化RePlugin流程与源码解析.docx_第6页
第6页 / 共13页
Android全面插件化RePlugin流程与源码解析.docx_第7页
第7页 / 共13页
Android全面插件化RePlugin流程与源码解析.docx_第8页
第8页 / 共13页
Android全面插件化RePlugin流程与源码解析.docx_第9页
第9页 / 共13页
Android全面插件化RePlugin流程与源码解析.docx_第10页
第10页 / 共13页
Android全面插件化RePlugin流程与源码解析.docx_第11页
第11页 / 共13页
Android全面插件化RePlugin流程与源码解析.docx_第12页
第12页 / 共13页
Android全面插件化RePlugin流程与源码解析.docx_第13页
第13页 / 共13页
亲,该文档总共13页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

Android全面插件化RePlugin流程与源码解析.docx

《Android全面插件化RePlugin流程与源码解析.docx》由会员分享,可在线阅读,更多相关《Android全面插件化RePlugin流程与源码解析.docx(13页珍藏版)》请在冰点文库上搜索。

Android全面插件化RePlugin流程与源码解析.docx

Android全面插件化RePlugin流程与源码解析

Android全面插件化RePlugin流程与源码解析

Android全面插件化RePlugin流程与源码解析

作者恋猫月亮

2017.07.2407:

11

字数4003

阅读405评论6喜欢13赞赏1RePlugin,360开源的全面插件化框架,按照官网说的,其目的是“尽可能多的让模块变成插件”,并在很稳定的前提下,尽可能像开发普通

App那样灵活。

那么下面就让我们一起深入$了解它吧。

(ps:

阅读本文请多参考源码图片(—八—)$、)

、介绍

RePlugin对比其他插件化,它的强大和特色,在于它只

Hook住了ClassLoader。

OneHook这个坚持,最大程度保证了稳定性、兼容性和可维护性,详见《全面插件化

RePlugin的使命》。

当然,OneHook也极大的提高了实现复

杂程度性,其中主要体现在:

增加了Gradle插件脚本,实现开发中自动代码修改与生成。

分割了插件库和宿主库的代码实现。

代码中存在很多不少

@deprecated、TODO和临时修改。

初始化、加载、启动等逻辑比较复杂。

图一Replugin项目结构

本篇将竭尽所能,为各位介绍其流程和内部实现,如果

存在一些地方存在纰漏,还请指出。

文章篇幅较长,需耐心阅读,阅读时可结合图片源码,同时欢迎收藏,或选择感兴趣点阅读,下面主要涉及:

二、ClassLoader基础知识。

 

七、Replugin启动Activity。

此处应有图

、ClassLoader基础知识

既然Replugin选择Hook住ClassLoader,那先简单介绍

ClassLoader的基本知识吧,如熟悉者请略过。

ClassLoader又叫类加载器,是专门处理类加载,

APP可以存在多个ClassLoader,它使用的是双亲代理模型,

如下图所示,创建一个ClassLoader,需要使用一个已有的

ClassLoader对象,作为新建的实例的ParentLoader。

抽象基

类ClassLoader

这样的条件下,一个App中所有的ClassLoader都联系

了起来。

当加载类时,如果当前ClassLoader未加载此类,就查询ParentLoader是否加载过,一直往上查找,如果存在就返回,如果都没有,就执行该Loader去执行加载工作。

这样避免了类重复加载的浪费。

其中常见的Loader有:

dex。

BootClassLoader是系统启动时创建的,一般不需要用到。

PathClassLoader是应用启动时创建的,只能加载内部

DexClassLoader可以加载外部的dex。

RePlugin中存在两个主要ClassLoaer:

PathClassLoader,也是唯一Hook住系统的Loader。

2、PluginDexClassLoader:

加载插件的Loader,继承

DexClassLoader。

用来做一些“更高级”的特性。

三、Replugin项目原理和结构分析

1、基础原理

简单来说,其核心是hook住了ClassLoader,在Activity

启动前:

记录下目标页ActivityA,替换成已自动注册在

AndroidManifest

中的坑位ActivityNS。

在ClassLoader截ActivityNS的创建,创建出ActivityA返回。

返回的

ActivityA占用着ActivityNS这个坑位,坑位由Gradle编译时自动生成在AndroidManifest中。

在编译时,replugin-replugin-library脚本,会替换代码中

的基础类和方法。

如下图【官方原理图】所示,替换的基类里会做一些初始化,所以这一块稍微有点入侵性。

此外,

replugin-host-library会生成AndroidManifest、配置相关信息、打包等,也由Gradle插件自动完成。

打包独立APK,或者打包为插件,可单可插,这就是

RePlugin。

官方原理图

2、项目结构

RePlugin整个项目结构,目前分为四个module,其中又

分为两个gradle插件module,两个library的java

本文主要分析library相关,如果对gradle

module,详细如开头【图

Replugin项目结构】

插件感兴趣的,可以查看结尾其他推荐。

2.1、replugin-host-gradle:

对应com.qihoo360.replugin:

replugin-host-gradle:

xxx依

赖,主要负责在主程序的编译期中生产各类文件:

根据用户的配置文件,生成HostBuildConfig类,方便插件框架读取并自定义其属性,如:

进程数、各类型占位坑的数量、是否使用AppCompat库、Host版本、pulgins-builtin.json文件名、内置插件文件名等。

自动生成带RePlugin插件坑位的AndroidManifest.xml文件,文件中带有如:

android:

theme="@style/Theme.AppCompat"android:

name="com.qihoo360.replugin.sample.host.loader.a.ActivityN1STTS0"

android:

exported="false"

android:

screenOrientation="portrait"android:

configChanges="keyboard|keyboardHidden|orientation|screenSize"/>

2.2、replugin-host-library:

对应com.qihoo360.replugin:

replugin-host-lib:

xxx依赖,

是一个Java工程,由主程序负责引入,是RePlugin的核心工程,负责初始化、加载、启动、管理插件等。

2.3、replugin-plugin-gradle:

对应com.qihoo360.replugin:

replugin-plugin-gradle:

xxx

是一个Gradle插件,由插件负责引入,主要负责在插件的编译期中:

配置插件打包相关信息;动态替换插件工程中的继承基类,如下,修改Activity的继承、Provider的重定向等。

/*LoaderActivity替换规则*/defprivatestaticloaderActivityRules=[

'android.app.Activity'

'com.qihoo360.replugin.loader.a.PluginActivity',

'android.app.TabActivity'

'com.qihoo360.replugin.loader.a.PluginTabActivity',

'android.app.ListActivity'

'com.qihoo360.replugin.loader.a.PluginListActivity',

'android.app.ActivityGroup'

'com.qihoo360.replugin.loader.a.PluginActivityGroup',

'android.support.v4.app.FragmentActivity':

'com.qihoo360.replugin.loader.a.PluginFragmentActivity',

'android.support.v7.app.AppCompatActivity':

'com.qihoo360.replugin.loader.a.PluginAppCompatActivity',

'android.preference.PreferenceActivity'

'com.qihoo360.replugin.loader.a.PluginPreferenceActivity',

'android.app.ExpandableListActivity'

'com.qihoo360.replugin.loader.a.PluginExpandableListActivity'

2.4、replugin-plugin-library:

对应com.qihoo360.replugin:

replugin-plugin-lib:

xxx依赖,

是一个Java工程,由插件端负责引入,主要提供通过“Java

反射”来调用主程序中

RePluginHostLibrary的相关接口,

 

PluginServiceClient

中的RePlugin、

其中的RePlugin、RePluginInternal、

都是反射宿主App:

replugin-host-library

RePluginInternal、PluginServiceClient类方法。

四、Replugin的ClassLoader。

这里主要介绍,宿主和插件使用的ClassLoader,以及它

们的创建和Hook住时机。

这是RePlugin唯一的Hook点,

而其中插件ClassLoader和宿主ClassLoader是相互关系的,如下图。

将就的图

1、宿主的ClassLoader

RePluginClassLoader,宿主的ClassLoader,继承

PathClassLoader,构造方法使用原ClassLoader,和原

ParentLoader是因为双亲代

ClassLoader的Parent生成。

其中

 

用于欺骗系统还处于原Loader,并且从原Loader中反射出常

用方法,用于重载方法中使用。

拷贝资源方式方法

宿主Loader

中,主要是重载了loadClass,其中从PMF

(RePlugin中公开接口类)中查找class,如果存在即返回插

件class,如果不存在就从原Loader中加载。

从而实现了对

加载类的拦截。

这里的PMF在加载class时,其实用的是下面【2、插

件的ClassLoader】:

PluginDexClassLoader,这个后面流程会讲到。

2、插件的ClassLoader

PluginDexClassLoader,继承DexClassLoader,构造时持

有了宿主的ClassLoader,从宿主ClassLoader中反射获取

loadClass方法,当自己的loadClass方法找不到类时,从宿

创建:

上面1、2中两个Loader,是宿主在初始化时创

建的,初始化时可以选择配置RePluginCallbacks,callback

中提供方法默认创建Loader,你也可以实现自定义的

ClassLoader,但是需要继承以上的Loader,如下图。

//初始化方式创建

RePlugin.getConfig().getCallbacks().createClassLoader(oClassLoader.getParent(),oClassLoader);RePluginCallbacks

Hook:

初始化时,PatchClassLoaderUtils会在Application

的attachBaseContextO中,通过patch(application)Hook住宿主的ClassLoader,patch内部如下图。

hookClassLoader

五、Replugin的相关类介绍

提前介绍一些功能类,后面就不做详细介绍。

1、RePlugin

RePlugin的对外入口类,提供install、uninstall、preload、startActivity、fetchPackageInfo、fetchComponentList,

fetchClassLoader等等统一的方法入口,用户操作的主要是它。

2、RePlugin.App:

RePlugin中的内部类,针对Application的入口类,所有针对插件Application的调用应从此类开始和初始化,想象成插件的Application吧。

3、PmBase:

RePlugin常用mPluginMgr变量表示,可以看作插件管理者。

初始化插件、加载插件等一般都是从它开始。

4、PluginContainers:

插件容器管理中心。

5、PmLocalImpl:

各种本地接口实现,如startActivity,

getActivityInfo,loadPluginActivity等。

6、PmInternalImpl:

类似Activity的接口实现,内部实现了真正startActivity的逻辑、还有插件Activity生命周期的接口。

准备好了吗,骚年

六、Replugin的初始化

那就是从Application初始化开始看起,枯燥的流程就

要开始了,忍住兄弟,我们能赢。

首先我们先看下面这流程图,大致了解启动流程:

将就的看吧

1、attachBaseContext

首先是从Application的attachBaseContext初始化开

始。

如下图,这里主要是配置RePluginConfig和

中的RePluginCallbacks提供了

RePluginCallbacks,然后根据Config去初始化插件。

值得注意的是,RePluginConfig

默认方法创建RePlugin的ClassLoader,还记得上面的介绍

吗?

看图看图

2、插件App.attachBaseContext

继续上面的流程,进入

RePlugin.App.attachBaseContext(this,c),如下图,这里主要

是初始化插件相关的进程、配置信息、插件的主框架和接口、根据默认路径、加载默认插件等。

插件的初始化从这里开始,其中主要为PMF.init()和PMF.callAttach()。

继续看图看图

3、主程序接口PMF.init()/PMF.callAttach()

先进入到PMF.init(),如下图,这里主要实例化了

PmBase类,并初始化了它,创建了内部使用的PmLocalImpl和PmInternalImp接口,同时Hook住主程序的

ClassLoader,替换为RePluginClassLoader,所以接下来的流

程,主要是在PmBase。

PMF.init(),看图吧

PmBase,按照项目中的变量名mPluginMgr,可以理解

为插件的管理者,它管理内部直接或间接的,管理着坑位分配、ClassLoader、插件、进程、启动停止页面的接口等,如

F图。

PmBase创建,还是看图

PmBase的初始化,也就是插件的初始化,这里会启动

各类进程,初始化各种默认插件集合,为后续加载做准备。

 

plugins-builtin.json和"plugins"文件夹下。

PmBase.init()看图看图

接着PMF.callAttach()其实就是PmBase.callAttach(),

如下图这里开始真正加载插件,初始化插件的

PluginDexClassLoader、加载插件、初始化插件环境和接口。

其中在执行p.load()的时候,会通过

Plugind.callAppLocked()创建插件的Application,并初始化。

PMF.callAttach()看图呗

以上是在主APP的初始化,深入PmBase中

Plugin.load()在加载时,会调用PluginDexClassLoader,通过类名加载Entry类,然后反射出create方法,执行插件的初

始化。

其中

Entry位于Plugin-lib库中。

这里初始化就去到

了插件中了,插件中初始化时,会通过反射的到宿主host类的方法。

4、Application的onCreate

这里主要是切换handler到主线程,注册各种广播接收

监听,如增加插件、卸载插件、更新插件,可以看出这里设计很多内部进程通信的。

七、Replugin启动Activity

 

版的,实际代码逻辑复杂多了,但是万变不离其宗,这里帮你梳理流程,描述一些关键的点,让你快速理解Activity的启动流程。

再将就下吧,看图

1、startActivity

RePlugin.startActivity开始,startActivity经历了Factory、

PmLocalImpl,其实大部分启动的逻辑其实主要在

PmInternalImpl中。

具体流程如下图,这里简化了实际代码,关键在于

loadPluginActivity。

这里获取了插件对应的坑位,然后保存了目标Activity的信息,通过系统启动坑位。

因为已经Hook住了ClassLoader,在loadClass时再加

载出目标Activity,这样坑位中承载的,便是绕过系统打开的目标Activity。

下面我们进入loadPluginActivity。

说了看

2、loadPluginActivity

loadPluginActivity其实是PmBase中的PmLocalImpl

内部方法。

如下图,这里主要是根据获取到ActivityInfo,然

后根据坑位去为目标Activity分配坑位。

其中

getActivityInfo是通过插件名称,获得插件对象

Plugin,Plugin可能是初始化中已加载的,如果未加载就加载返回,然后根据Plugin中缓存的坑位信息,返回

ActivityInfo。

下面进入allocActivityContainer看坑位的分配,只有分

配到坑位,插件的Activity才可以启动,这是一个IPC过程。

看图没?

2、allocActivityContainer

allocActivityContainer在类PluginProcessPer

中,还记

得我们在PmBase.init()时初始化过它么?

分配坑位也是

RePlugin的核心之一。

在allocActivityContainer中

主要逻辑是

bindActivity,如下图,bindActivity去找到目标Activity匹配的容器,然后加载目标Activity判断是否存在,并建立映

射,返回容器。

然后分配的逻辑,在PluginContainers.alloc

中。

看我大图

3、PluginContainers.alloc

 

alloc/alloc2方法分配坑位,最后都是到了allocLocked

 

如果存在未启动的坑位,就使用它。

如果没有就找最老的:

已经被释放的、或者时间最老的。

如果还不行,那么挤掉最老的一个。

看图说话

4、PulginActivity

上面的流程总结,是替换目标Activity,加载插件,分

配坑位,启动目标坑位,拦截ClassLoader的loadClass去加载返回目标Activity。

这个时候启动的Activity还不完整,从模块框架中我们

知道,在编译时,RePlugin会把继承的Activity替换为如

PluginActivity(当前还有AppComPluginActivity等)。

这时候加载启动的目标Activity,其实是继承了PluginActivity。

中的一些方法,

如下图,PluginActivity重载Activity

实现了Activity的补全和自定义操作,如坑位管理,启动宿头晕目眩了没?

为了实现OneHook这个信念,RePlugin实现了复杂的流程,从代码中可以看出,这些年作者们从中走的的各种坑、各种妥协与坚持、复杂的技术积累、已经经历了多年的严酷考验。

不知道有多少人能完整看到这,码字不易,如有疏漏还

是多多包涵,由于篇(tou)幅(Ian)原因,关于Service等

的就不多做叙述了,不知道本文对你是否能有些帮助,欢迎留言讨论。

最后说“一”句

为什么要去了解一个库实现原理呢?

学习框架的架构

思想?

这是一个原因。

但是归根结底,是帮助你在使用库的

中,能靠自己解决各种问题。

程序员的日常一般都忙于

各种工作,各种技术群中的大佬们,大部分时候,没办法

解答你的各种咨询,所以使用它、了解它、多尝试靠自己去探索突破吧。

其他推荐

RePIuginGithub官方库

RePIugin源码解析之repIugin-host-gradIe(宿主gradIe插件)

@osan

@osan

RePlugin源码解析之replugin-plugin-gradle(插件的gradle插件)

ToMyGithub注意到了吗?

最后的总是我!

Android程序员的日常

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > IT计算机 > 电脑基础知识

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2