利用gradle插件实现将APP打包后上传到蒲公英以及发送消息到钉钉

589 阅读5分钟

对于gradle中相关代码的解释这里引用的是字节跳动团队的推文

深入理解Gradle框架之一:Plugin, Extension, buildSrc

但是还是简单的介绍一下,就拿我们常见的app/build.gradle文件来说。 我们最先看到的其实是

apply plugin: 'com.android.application' 他告诉了gradle,我们使用了一个名字为com.android.application的插件(关于插件的定义等在之前我已经说过了 Gradle Transform的定义过程),接下来常见的就是

android{}
dependencies{}

这两个叫做Extension,对于我们来说其实就是Javabean,是为插件提供数据的,在插件的task开始执行时需要用到这些数据。比如我定义一个TestExtension

class TestExtension{
    String name
    String userNo
    String  cookie
}

在app/build.gradle中使用

test {
    name "testStr"
    userNo "testUserNo"
    cookie "testCookie"
}

因为这是我自定义的一个extension,所以要在plugin中添加这个Extension,

def customExtensions = project.getExtensions().create("test", TestExtension.class)

其实就是在自定插件的apply方法中通过create创建一个extension,注意这里的“test”就是在build.gradle中添加这个extension的名字。好了到此准备工作就做完了。那么回到题目所述问题,打包完成之后,先上传到蒲公英,后发消息到钉钉。这里就涉及到几个问题

  1. 在哪儿获取打包之后
  2. 如何创建一个任务
  3. 如何在打包之后插入一个上传任务
  4. 在插件中的上传文件如何编写

这里涉及到执行顺序的问题,那么我们就看看gradle的执行流程

主要分为三个阶段,分别为初始化阶段、配置阶段和执行阶段

  • 初始化阶段:就是执行 settings.gradle,它的下一个阶段是配置阶段
  • 配置阶段:解析每个 project 中的 build.gradle。解析每个子目录中的 build.gradle。在这两个阶段之间,我们可以加一些定制化的 Hook。这当然是通过 API 来添加的。这个阶段完成之后,整个 build 的 project 以及内部的 Task 关系就确定了。一个 Project 包含很多 Task,每个 Task 之间有依赖关系此时会建立一个有向图来描述 Task 之间的依赖关系。所以,我们可以添加一个 HOOK,即当 Task 关系图建立好后,执行一些操作。
  • 执行阶段:就是按顺序执行配置阶段完成的有向无环图中的task。一个新建的APP,点击安装时他的构建过程如下

可以看到这里最后一步自然是打包assembleDebug,当然如果是release包的话这里就应该是assembleRelease。看到这里我们就解决了第一个问题,我们第一个插入任务的地方是在assemblexxx这个task之后,通过如下代码可找到这个任务

def assembleTask=project.tasks.findByName("assembleDebug")

当然这个创建的代码是在自定义plugin的apply中。接下来是第二个问题,如何创建一个task,其实他与extension的创建差不多,比如这里的uploadTask

UploadToPgyTask task = project.tasks.create("uploadTask", UploadToPgyTask.class)

而这个类的定义如下

class UploadToPgyTask extends DefaultTask {
    def cookie = ""
    def userNo = ""

    void init(String userNo,String cookie) {
        setDescription("test Task")
        setGroup("releaseHelPer")
        this.userNo = userNo
        this.cookie = cookie
    }

    @TaskAction
    void upLoadToPyg() {
        System.out.print("执行了上传任务到蒲公英\n")

        NetApi api = NetWorkManager.getInstent().getNetApi()
        Call<GiftStateBean> call = api.getGiftBagRewardState(userNo, cookie)
        Response<GiftStateBean> response = call.execute()

        if (response.successful)
            System.out.print("上传成功")
    }

}

可以看到如果要定义task的话需要继承DefaultTask,并且利用@TaskAction注解来指定task执行时的入口,至于里面的上传使用的是retrofit,用法就跟在APP中使用一样,只不过这里的上传任务用的是同步方法。现在的第二个问题也解决了。那就看第三个问题,如何保证执行顺序,其实就一行代码

assembleTask.finalizedBy(task)

接下来就是最后一个问题了上传文件。这里给的是一段普通的post请求,如果是文件上传的话用retrofit也是很简单的,只是需要在定义call的时候定义成文件类型,调用跟这里的一样(不懂的可以看 retrofit的使用 一文),至此整个流程就结束了,那么完整的plugin代码如下

class TestPlugin implements Plugin<Project> {

    @Override
    void apply(Project project) {
       project.getExtensions().create("test", TestExtension.class)

        //其实是gradle的回调,它会在配置阶段结束后调用
        project.afterEvaluate {
            //获取android这个extension下的属性值
            Collection<ApplicationVariant> appVarients = ((AppExtension) project.getExtensions().getByName("android")).getApplicationVariants()
            for (ApplicationVariant applicationVariant : appVarients) {
                //判断当前的buildType:debug或者是release
                if (applicationVariant.getBuildType().getName().equalsIgnoreCase("debug")) {
                    //获取自定义extension的值
                    String deliveredName = ((TestExtension) project.getExtensions().getByName("test")).name
                    String deliveredUserNo = ((TestExtension) project.getExtensions().getByName("test")).userNo
                    String deliveredCookie = ((TestExtension) project.getExtensions().getByName("test")).cookie
                    print("CustomPlugin ==>>name==>> $deliveredName==>>userNo==>>$deliveredUserNo==>>cookie==>>$deliveredCookie")

                    //创建上传蒲公英的task
                    UploadToPgyTask task = project.tasks.create("uploadTask", UploadToPgyTask.class)
                    task.init(deliveredUserNo,deliveredCookie)

                    //找到系统打包的那个task,当然这里还可以根据buildType获取Release的
                    def assembleTask=project.tasks.findByName("assembleDebug")
                    //把上传蒲公英的任务放到assemble之后
                    assembleTask.finalizedBy(task)

                    //创建发送消息到钉钉的任务
                    SendMsgToDingDingTask secondTask = project.tasks.create("sendMsgTask", SendMsgToDingDingTask.class)
                    secondTask.init()
                    //该任务放到上传任务之后
                    task.finalizedBy(secondTask)

                }
            }
        }
    }
}

我们在app/build.gradle中使用该插件

apply plugin: 'com.android.application'
apply plugin: 'com.mwy.test'

test {
    name "testStr"
    userNo "6247133"
    cookie "54NaELPpO165t4ZTfy5bUZBegNcfuRU1+Qk5tJGxVpc="
}

直接点击运行,我们看build日志 首先在项目开始编译之前会读取配置的参数

然后会执行我们插入的task

可以看到确实是在assemble之后掺入了上传的任务,上传任务完成之后又执行了发送消息的任务,最后才是build success。 最后整个项目的目录结构为

这里还需要注意的是既然在插件中使用retrofit那么就要添加他的引用