美文网首页
gradle插件字节码插桩(一),注册使用Transform

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

作者: 和平菌 | 来源:发表于2017-11-08 17:55 被阅读0次

    前面介绍了如何开发一个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

    相关文章

      网友评论

          本文标题:gradle插件字节码插桩(一),注册使用Transform

          本文链接:https://www.haomeiwen.com/subject/bwyymxtx.html