Replugin插件化技术解读之框架初始化、插件安装与加载(一)

本文深入解析Replugin的初始化过程,从RepluginApplication的attachBaseApplication开始,涉及PmBase.init、坑位Activity的初始化、PmHostSvc的建立以及常驻与非常驻进程间的通信。通过gradle配置初始化Replugin,并探讨插件安装卸载的管理方式。
摘要由CSDN通过智能技术生成
一、前言
如果使用过一些三方库的都知道,大部分引入库都是在Application中初始化的,所以在阅读Replugin源码前,不用看官方宿主接入wiki基本就能猜到,肯定是在替换自定义Application中对插件框架初始化的,本章就是以此为契入点,走读源码展开整体框架初始化流程分析,由于整个Replugin架构逻辑还是相当复杂的,为了方便走读逻辑,附上的代码几乎都添加了注释说明方便大家理解,大家可不要忽视哦!!!!!

Replugin源码地址: https://github.com/Qihoo360/RePlugin

(由于Replugin官方提供的项目不支持clone直接编译运行,为了方便代码走读和编译,直接使用了官方FAQ中提供的一位大神的构建升级版本,代码可能与Replugin最新版本有轻微出入,但是主体流程变化不大,参考:https://note.youdao.com/share/?id=61c0f27494c5a466a40642829da2938c&type=note#/)

二、框架初始化

第1步:RepluginApplication就是Replugin提供给三方应用来继承的Application类,继承了RepluginApplication后,当应用进程被系统创建时就会自动调用attachBaseApplication方法(至于为什么会自动回调attachBaseApplication,不明白的同学自行百度啦),OK,锁定这里,Replugin的初始化逻辑就是放在这里.

protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
RePluginConfig c = createConfig();
if (c == null) {
    c = new RePluginConfig();
}
RePluginCallbacks cb = createCallbacks();
if (cb != null) {
    c.setCallbacks(cb);
}
//1.框架初始化入口
RePlugin.App.attachBaseContext(this, c);
}
第2步 RePlugin.App.attachBaseContext是一个内部类方法,会执行所有的初始化的相关逻辑,其中IPC.init方法会去区分插件管理常驻进程和非常驻进程,不同进程在这里的实现逻辑是不一样的,这个下面会详细说明。另外还要注意的一点是利用HostConfigHelper反射获取动态编译自动生成在gen目录下的RePluginHostConfig.java文件,以便初始化的时候根据配置的参数展开。

RePlugin.java

public static void attachBaseContext(Application app, RePluginConfig config) {
    ...
    //1. 初始化应用自己的classloder和ApplicationContext,方便框架内部调用
    RePluginInternal.init(app);
    sConfig = config;

    //2. RepluginConfig在这里初始化其内部RePluginCallbacks,RePluginEventCallbacks这两个对象默认值
    //三方应用在继承插件框架的时候也可以外部set
    sConfig.initDefaults(app);

    //3. 根据当前进程名来判断是UI进程还是专门管理插件的常驻进程,常驻进程默认名称是:GuardService,可以外部set
    IPC.init(app);

    //4. 这里通过调用HostConfigHelper静态方法来加载初始化自己,会通过反射读取gradle动态编译自动生成的配置类RePluginHostConfig数据
    //比如是否使用APPCOMPAT、坑数量等等
    HostConfigHelper.init();

    // FIXME 此处需要优化掉
    AppVar.sAppContext = app;
    // Plugin Status Controller
    PluginStatusController.setAppContext(app);
    //5. 主要初始化核心类PmBase,按照常驻进程和UI进程来初始化不同逻辑
    PMF.init(app);
    //6.主要执行插件挂载操作
    PMF.callAttach();

    sAttached = true;
}
第3步: PMF.init方法中会去初始化PmBase sPluginMgr,这个类很重要,是整个框架初始化流程中个人认为最核心的类,后面很多地方都会看到此类身影,后面会详细说明。同时,Replugin宣传中最大的"卖点"特性:唯一Hook点,就是在这PatchClassLoaderUtils.patch方法中实现的,Hook的流程会在后面单独抽出一篇博文来讲解。

PMF.java

public static final void init(Application application) {
        setApplicationContext(application);

        //1.主要是初始化sPluginProcessIndex值,这个值主要用来区分UI进程和插件自定义进程
        //插件进程名称类似 xxx.xx:p0, xxx.xx:p1, xxx.xx:p2
        // 如果是UI进程则返回-1,其他进程则返回-100,-99,-98
        PluginManager.init(application);

        //2. 初始化框架核心类PmBase,构造函数中会初始化生成Activity Service Provider的相关“坑位”
        // 初始化init时会区分插件管理常驻进程和非常驻进程,常驻进程中会去扫描所有内置插件并存储在PmBase内部的一个Map中
        sPluginMgr = new PmBase(application);
        sPluginMgr.init();

        //3. 将PmBase的mLocal和mInternal对象赋值给Factory和Factory2,后面加载插件初始化的时候会用到
        Factory.sPluginManager = PMF.getLocal();
        Factory2.sPluginManager = PMF.getInternal();

        //4. Replugin唯一hook点 hook系统ClassLoader
        PatchClassLoaderUtils.patch(application);
    }
第4步: 上面提到过,PmBase这个类很核心,重点讲解下,首先先走读下new PmBase()的代码,看看PmBase构造函数中干了哪些事情。

 PmBase(Context context) {
        //
        mContext = context;
        // TODO init
        //init(context, this);
        //1.如果当前进程是UI进程或者plugin进程,初始化Provider和Services的临时“坑位”
        if (PluginManager.sPluginProcessIndex == IPluginManager.PROCESS_UI || PluginManager.isPluginProcess()) {
            String suffix;
            if (PluginManager.sPluginProcessIndex == IPluginManager.PROCESS_UI) {
                suffix = "N1";
            } else {
                suffix = "" + PluginManager.sPluginProcessIndex;
            }
            //com.XXX.XXX.loader.p.Provider.N1   //com.XXX.XXX.loader.p.Provider.0 或者 com.XXX.XXX.loader.p.Provider.1
            //mContainerProviders主要是用来存储宿主Provider坑位的,区分进程
            mContainerProviders.add(IPC.getPackageName() + CONTAINER_PROVIDER_PART + suffix);
            //com.XXX.XXX.loader.s.Service.N1   //com.XXX.XXX.loader.s.Service.0 或者 com.XXX.XXX.loader.s.Service.1
            //mContainerServices要是用来存储宿主Service坑位的&#x
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值