gradle插件字节码插桩(一),注册使用Transform

前面介绍了如何开发一个gradle插件,那么这次将分享一下如何进行插桩。

关于Transform的介绍和用法网上介绍的比较多,我就不再重复写了。我理解的就是Gradle在1.5以后提供了一个Transfrom API,允许用户在编译的过程中再去修改字节码。而Transfrom相当于是一个字节码的过滤器,有一个TransfromManager对他们进行管理,从一个Transfrom流入,然后对字节码进行加工处理以后再输出,然后流入下一个Transfrom,直到所有的Transfrom过滤处理完成。

那么我们的Transfrom就需要注册到TransfromManager中去。

首先第一步就是创建一个Transfrom,创建的方式就是继承一个抽象类Transform。关于该抽象类里面的其他方法的介绍,网上也有很多资料来参考,我主要介绍一下处理字节码的方法transform()

public abstract void transform(
            @NonNull Context context,
            @NonNull Collection<TransformInput> inputs,
            @NonNull Collection<TransformInput> referencedInputs,
            @Nullable TransformOutputProvider outputProvider,
            boolean isIncremental) throws IOException, TransformException, InterruptedException;

Transform的inputs有两种类型,一种是目录,一种是jar包,要分开遍历


println("注册的Transform执行了")

 // 分开对Jar和目录进行遍历
        inputs.each { TransformInput input ->
            //对类型为“文件夹”的input进行遍历
            input.directoryInputs.each { DirectoryInput directoryInput ->


                //文件夹里面包含的是我们手写的类以及R.class、BuildConfig.class以及R$XXX.class等
                //我们要在.class文件里插桩就在这里操作
               [......插入处理字节码文件的代码]

                // 获取output目录
                def dest = outputProvider.getContentLocation(directoryInput.name,
                        directoryInput.contentTypes, directoryInput.scopes,
                        Format.DIRECTORY)

                // 将input的目录复制到output指定目录
                FileUtils.copyDirectory(directoryInput.file, dest)
            }
            //对类型为jar文件的input进行遍历
            input.jarInputs.each { JarInput jarInput ->

                //jar文件一般是第三方依赖库jar文件

                // 重命名输出文件(同目录copyFile会冲突)
                def jarName = jarInput.name
                def md5Name = DigestUtils.md5Hex(jarInput.file.getAbsolutePath())
                if (jarName.endsWith(".jar")) {
                    jarName = jarName.substring(0, jarName.length() - 4)
                }
                //生成输出路径
                def dest = outputProvider.getContentLocation(jarName + md5Name,
                        jarInput.contentTypes, jarInput.scopes, Format.JAR)
                //将输入内容复制到输出
                FileUtils.copyFile(jarInput.file, dest)
            }
        }

从input处理完file后一定要对外进行输出。

注意:
这里使用到了apache-common包,我们需要引入一下不然会报错

  compile "commons-io:commons-io:+"
  compile 'commons-codec:commons-codec:+'

(这两个包在gradle里引入uri我也是找了好久才找到的。。。。目前我们这里的Transform相当于什么也没有做,然后将file再原封不动的输出了。

写好Transform以后我们就需要对Transform进行注册,注册的方式呢就是在我们的Plugin类里,还是那个void apply(Project project) 方法中

  System.out.println("------------------注册了Transform----------------------");
   def android = project.extensions.findByType(AppExtension)
   android.registerTransform(new ShujuliTransform(project))

然后我们上传后,再去刷新我们使用插件的项目。这个时候就需要打包的时候才能执行Transform。

对项目进行Clean Project,然后刷新Gradle,再Build Apks

我们在Gradle打控制台看到我们打印的那段信息,说明我们成功注册了我们的Transform

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,323评论 19 139
  • title: Android AOP之字节码插桩author: 陶超description: 实现数据收集SDK时...
    陶菜菜阅读 38,389评论 40 182
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 175,103评论 25 709
  • 前言 replugin-plugin-gradle 是 RePlugin 插件框架中提供给replugin插件用的...
    osan阅读 11,939评论 8 33
  • 不知何时,她总会出现在我的脑海里;不知何时,我的嘴边总会提起她的名字;不知何时,我的笑容总为她绽放。更不知何时,那...
    安舍Y阅读 897评论 0 0