RePlugin教程(plugin-gradle代码结构)

replugin-plugin-gradle

  作用:是一个Gradle插件,由插件负责引入,主要负责在插件的编译期中:配置插件打包相关信息;动态替换插件工程中的继承基类。

1.ReClassPlugin

作用:继承于Plugin<Project>,实现了apply方法。

2.PluginDebugge(命令功能类)

作用:基于adb shell + am 命令,实现 发送广播,push apk 等功能

代码:

public boolean startHostApp() {

   if (isConfigNull()) {

       return false

   }

   String cmd = "${adbFile.absolutePath} shell am start -n \"${config.hostApplicationId}/${config.hostAppLauncherActivity}\" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER"

   if (0 != CmdUtil.syncExecute(cmd)) {

       return false

   }

   return true

}

3.def assembleTask(根Task)

作用:获取assemble task(即打包apk的task),后续的task需要依赖此task,比如安装插件的task,肯定要等到assemble task打包生成apk后,才能去执行。

4.installPluginTask.doLast(安装Task)

作用:依赖于assemble task,任务内容为启动宿主 -> 卸载插件 -> 强制停止宿主 -> 启动宿主 -> 安装插件。

5.Transfrom

Transform 是 Android Gradle API ,允许第三方插件在class文件转为dex文件前操作编译完成的class文件,这个API的引入是为了简化class文件的自定义操作而无需对Task进行处理。

实现方法:实现一个继承自Transform的自定义 Transform 类。

                 通过registerTransform(@NonNull Transform transform, Object... dependencies)注册自                   定义 Transform 类。

6.includedInjectors()(注入器集合方法)

作用:返回用户未忽略的注入器的集合:

(1)LoaderActivityInjector 替换插件中的Activity的继承相关代码 为 replugin-plugin-library 中的XXPluginActivity父类

(2)LocalBroadcastInjector 替换插件中的LocalBroadcastManager调用代码 为 插件库的调用代码。

(3)ProviderInjector 替换 插件中的 ContentResolver 调用代码 为 插件库的调用代码

(4)ProviderInjector2 替换 插件中的 ContentProviderClient 调用代码 为 插件库的调用代码

(5)GetIdentifierInjector 替换 插件中的 Resource.getIdentifier 调用代码的参数 为 动态适配的参数

7.LoaderActivirtyInjector(Activity注入器)

作用:用来修改插件中XXActivity类中的顶级XXActivity父类 为 XXPluginActivity父类。

其init()指定了 Activity 替换规则,只替换那些顶级Activity父类为 replugin-plugin-lib 库中的 XXPluginActivity。

def private static loaderActivityRules = [

         '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'

]

8.LocalBroadcastInjector(广播注入器)

作用:实现了替换插件中的LocalBroadcastManager的方法调用为插件库的PluginLocalBroadcastManager中的方法调用。

def injectClass(ClassPool pool, String dir, Map config) {

    ...

    try {

        // 不处理 LocalBroadcastManager.class

        if (filePath.contains('android/support/v4/content/LocalBroadcastManager')) {

            println "Ignore ${filePath}"

            return super.visitFile(file, attrs)

        }

        stream = new FileInputStream(filePath)

        ctCls = pool.makeClass(stream);

        // println ctCls.name

        if (ctCls.isFrozen()) {

            ctCls.defrost()

        }

        /* 检查方法列表 */

        ctCls.getDeclaredMethods().each {

            it.instrument(editor)

        }

        ctCls.getMethods().each {

            it.instrument(editor)

        }

        ctCls.writeFile(dir)

    }

    ...

}

(filePath.contains('android/support/v4/content/LocalBroadcastManager'):避免替换掉v4包中的源码实现。

9.ProviderInjector(ContentResolver注入器)

作用:主要用来替换插件中的ContentResolver相关的方法调用为插件库的PluginProviderClient中的对应方法调用。

public static def includeMethodCall = ['query',

                                       'getType',

                                       'insert',

                                       'bulkInsert',

                                       'delete',

                                       'update',

                                       'openInputStream',

                                       'openOutputStream',

                                       'openFileDescriptor',

                                       'registerContentObserver',

                                       'acquireContentProviderClient',

                                       'notifyChange',

]

10.ProviderInjector2(内容注入器)

作用:主要用来替换插件中的ContentProviderClient相关的方法调用。

public static def includeMethodCall = ['query', 'update']

static def includeMethodCall中定义了需要处理的目标方法名

public class ProviderExprEditor2 extends ExprEditor {

    static def PROVIDER_CLASS = 'com.qihoo360.loader2.mgr.PluginProviderClient2'

    @Override

    void edit(MethodCall m) throws CannotCompileException {

      ...

      replaceStatement(m, methodName, m.lineNumber)

      ...

    }

    def private replaceStatement(MethodCall methodCall, String method, def line) {

        methodCall.replace('{$_ = ' + PROVIDER_CLASS + '.' + method + '(com.qihoo360.replugin.RePlugin.getPluginContext(), $$);}')

        println ">>> Replace: ${filePath} Provider.${method}():${line}"

    }

}

PROVIDER_CLASS指定了对应的替代实现类

replaceStatement(...)中,替换方法体:

替换query和update:

replace statement:'{$_ = ' + PROVIDER_CLASS + '.' + method + '(com.qihoo360.replugin.RePlugin.getPluginContext(), $$);}'

11.GetIdentifierInjector(动态参数注入器)

作用:主要用来替换插件中的Resource.getIdentifier方法调用的参数为动态适配的参数。

public class GetIdentifierExprEditor extends ExprEditor {

    public def filePath

    @Override

    void edit(MethodCall m) throws CannotCompileException {

        String clsName = m.getClassName()

        String methodName = m.getMethodName()

        if (clsName.equalsIgnoreCase('android.content.res.Resources')) {

            if (methodName == 'getIdentifier') {

                m.replace('{ $3 = \"' + CommonData.appPackage + '\"; ' +

                        '$_ = $proceed($$);' +

                        ' }')

                println " GetIdentifierCall => " +'{ $3 = \"' + CommonData.appPackage + '\"; ' +

                        '$_ = $proceed($$);' +

                        ' }'

                println " \n";

                println " GetIdentifierCall => ${filePath} ${methodName}():${m.lineNumber}"

            }

        }

    }

}

edit( )中,遍历到调用方为android.content.res.Resources且方法为getIdentifier的MethodCall,动态适配这些MethodCall中的方法参数。

猜你喜欢

转载自blog.csdn.net/qq_35159110/article/details/81630247