美文网首页Android进阶之路Android开发Android开发经验谈
手把手教你实现一个 Gradle Tansform 实例

手把手教你实现一个 Gradle Tansform 实例

作者: Joker_Wan | 来源:发表于2019-12-18 13:39 被阅读0次

    关于Gradle Transform API 的详细分析我之前有一篇文章Android Gradle Transform 详解已经讲到了,这里不再重复,直接开始上手撸代码,还没看过前面一篇博客的同学建议先去看看,好帮助理解。

    1、 新建 Android Library Module :plugin,清空plugin的build.gradle文件中的内容,然后修改成如下内容

    apply plugin: 'groovy'
    apply plugin: 'maven'
    dependencies {
        implementation gradleApi() //gradle sdk
        implementation localGroovy() //groovy sdk
    
        implementation 'com.android.tools.build:gradle:3.4.1'
    }
    repositories {
        jcenter()
    }
    
    uploadArchives {
        repositories.mavenDeployer {
            //本地仓库路径,以放到项目根目录下的 repo 的文件夹为例
            repository(url: uri('../repo'))
    
            //groupId ,自行定义,组织名或公司名
            pom.groupId = 'com.jokerwan'
    
            //artifactId,自行定义,项目名或模块名
            pom.artifactId = 'autotrack.android'
    
            //插件版本号
            pom.version = '1.0.0'
        }
    }
    

    我们这里是发布plugin插件到本地仓库,上面配置的groupIdartifactIdversion属性能容都是可以自定义的,当应用程序引用这个插件时会用到这些信息。通过repositories属性,可以把uri配置在本地目录,这样就可以把maven设置成本地仓库,我们目前把仓库配置到当前Project根目录下的repo目录。

    2、 删除plugin/src/main目录下的所有文件,新建groovy目录

    因为插件我们用的是groovy语言开发的,所以需要放到groovy目录下。接着再groovy目录下新建一个package com.jokerwan.demo.plugin来存放Transform类文件

    3、 创建Transform类

    在包com.jokerwan.demo.plugin下创建JokerWanTransform.groovy类,直接new一个file,名称为“JokerWanTransform.groovy”,代码如下:

    package com.jokerwan.demo.plugin
    
    import com.android.build.api.transform.*
    import com.android.build.gradle.internal.pipeline.TransformManager
    import org.apache.commons.codec.digest.DigestUtils
    import org.apache.commons.io.FileUtils
    import org.gradle.api.Project
    
    class JokerWanTransform extends Transform {
    
        private static Project project
        private static final String NAME = "JokerWanAutoTrack"
    
        JokerWanTransform(Project project) {
            this.project = project
        }
    
        @Override
        String getName() {
            return NAME
        }
    
        /**
         * 需要处理的数据类型,有两种枚举类型
         * CLASSES 代表处理的 java 的 class 文件,RESOURCES 代表要处理 java 的资源
         * @return
         */
        @Override
        Set<QualifiedContent.ContentType> getInputTypes() {
            return TransformManager.CONTENT_CLASS
        }
    
        /**
         * 指 Transform 要操作内容的范围,官方文档 Scope 有 7 种类型:
         * 1. EXTERNAL_LIBRARIES        只有外部库
         * 2. PROJECT                   只有项目内容
         * 3. PROJECT_LOCAL_DEPS        只有项目的本地依赖(本地jar)
         * 4. PROVIDED_ONLY             只提供本地或远程依赖项
         * 5. SUB_PROJECTS              只有子项目。
         * 6. SUB_PROJECTS_LOCAL_DEPS   只有子项目的本地依赖项(本地jar)。
         * 7. TESTED_CODE               由当前变量(包括依赖项)测试的代码
         * @return
         */
        @Override
        Set<? super QualifiedContent.Scope> getScopes() {
            return TransformManager.SCOPE_FULL_PROJECT
        }
    
        @Override
        boolean isIncremental() {
            return false
        }
    
        static void printCopyRight() {
            println()
            println("******************************************************************************")
            println("******                                                                  ******")
            println("******                欢迎使用 JokerWanTransform 编译插件               ******")
            println("******                                                                  ******")
            println("******************************************************************************")
            println()
        }
    
        @Override
        void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {
            printCopyRight()
    
            TransformOutputProvider outputProvider = transformInvocation.getOutputProvider()
    
            // Transform 的 inputs 有两种类型,一种是目录,一种是 jar 包,要分开遍历
            transformInvocation.inputs.each { TransformInput input ->
                input.jarInputs.each { JarInput jarInput ->
                    // 处理jar
                    processJarInput(jarInput, outputProvider)
                }
    
                input.directoryInputs.each { DirectoryInput directoryInput ->
                    // 处理源码文件
                    processDirectoryInput(directoryInput, outputProvider)
                }
            }
    
        }
    
        void processJarInput(JarInput jarInput, TransformOutputProvider outputProvider) {
            // 重命名输出文件(同目录copyFile会冲突)
            def jarName = jarInput.name
            def md5Name = DigestUtils.md5Hex(jarInput.file.getAbsolutePath())
            if (jarName.endsWith(".jar")) {
                jarName = jarName.substring(0, jarName.length() - 4)
            }
    
            File dest = outputProvider.getContentLocation(
                    jarName + md5Name,
                    jarInput.getContentTypes(),
                    jarInput.getScopes(),
                    Format.JAR
            )
    
            // TODO do some transform
    
            // 将 input 的目录复制到 output 指定目录
            FileUtils.copyFile(jarInput.getFile(), dest)
        }
    
        void processDirectoryInput(DirectoryInput directoryInput, TransformOutputProvider outputProvider) {
            File dest = outputProvider.getContentLocation(
                    directoryInput.getName(),
                    directoryInput.getContentTypes(),
                    directoryInput.getScopes(),
                    Format.DIRECTORY
            )
    
            // TODO do some transform
    
            // 将 input 的目录复制到 output 指定目录
            FileUtils.copyDirectory(directoryInput.getFile(), dest)
        }
    }
    

    我们在transform方法里面,先打印一个提示信息,然后分别遍历目录和jar包,在这里我们仅仅把所有的输入文件拷贝到目标目录下,并没有对文件进行任何处理。这里需要注意的是,即使我们对文件没有任何处理,任然需要将所有的输入文件拷贝到目标目录下,否则下一个Task就没有TansformInput了,如果我们将 input 的目录复制到 output 指定目录,最后会导致打包的apk缺少.class文件

    4、 创建plugin

    在包com.jokerwan.demo.plugin下创建JokerWanPlugin.groovy类,并将JokerWanTransform类注册进去

    class JokerWanPlugin implements Plugin<Project> {
        void apply(Project project) {
            AppExtension appExtension = project.extensions.findByType(AppExtension.class)
            appExtension.registerTransform(new JokerWanTransform(project))
        }
    }
    

    JokerWanPlugin实现了Plugin<Project>接口中的apply(Project project)方法,获取一个appExtension对象,然后调用其registerTransform方法将JokerWanTransformNew的实例注册进去

    5、 创建properties文件

    在plugin/src/main目录下新建目录 resources/META-INF/gradle-plugins,接着在此目录下新建文件com.jokerwan.android.properties,文件内容如下:

    implementation-class=com.jokerwan.demo.plugin.JokerWanPlugin
    

    文件名com.jokerwan.android就是用来指定插件名称的,apply该组件时会用到,即

    apply plugin: 'com.jokerwan.android'
    

    “=”号后面的内容就是我们插件类JokerWanPlugin的全类名

    6、 构建plugin

    执行plugin的uploadArchives任务构建plugin

    构建成功之后,在项目的根目录会生成一个repo目录,里面存放的就是plugin插件的目标文件。构建成功输出信息如下:


    7、 添加对插件的依赖

    7.1、 修改项目根目录下的build.gradle文件
    7.2、 修改app/build.gradle文件

    8、 构建应用程序

    可以通过命令行进行编译

    ./gradlew assembleDebug
    

    如果编译没有报错的话并且看到相应的输出信息,就可以说明上面定义的JokerWanTransform已经成功运行了。编译成功输出信息如下:

    demo代码如下
    https://github.com/isJoker/TestTransform

    相关文章

      网友评论

        本文标题:手把手教你实现一个 Gradle Tansform 实例

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