定制Gradle任务自动打包jar

本文介绍如何在Android开发中利用Gradle自定义打包任务,包括创建Jar文件、调整依赖关系及实现自动化打包流程。

日常Android开发中,很大部分不需要自定义Gradle插件,但是需要定制一些task来满足需求,比如自定义打jar包,本文就借自定义打包来讲讲gradle的task使用方法和如何利用现在的task修改依赖关系。

自定义打包在N年前我也曾写过一篇博文,[使用gradle打包指定包名和类的jar](http://www.alloyteam.com/2015/03/shi-yong-gradle-da-bao-zhi-ding-bao-ming-he-lei-di-jar/),这是刚开始学习gradle时的做法,实现方法也就是在原有的gradle文件上建立一个Jar类型的task然后依赖编译过程的某个task然后调用相关apip实现自定义的功能

task makeJar(type:org.gradle.api.tasks.bundling.Jar) {
    //指定生成的jar名
    baseName 'sdk'
    //从哪里打包class文件
    from('build/intermediates/classes/debug/org/cmdmac/cloud/pluginsdk/')
    //打包到jar后的目录结构 
    into('org/cmdmac/cloud/pluginsdk/')
    //去掉不需要打包的目录和文件 
    exclude('test/', 'BuildConfig.class', 'R.class')
    //去掉R$开头的文件 
    exclude{ it.name.startsWith('R$');} 
} 
 
makeJar.dependsOn(clearJar, build)
这种方式可以达到目的,但是有个问题是,这个task需要在命令行./gradlew makeJar执行或者在Androd Studio的gradle task界面上手动触发,一般我们运行生成apk并运行都是直接点run的,这个过程是不会触发我们定义的task的,原因是原有的task依赖链中没有makeJar,那如何做到我们点run就能执行的自定义的task呢?

由前面的原因分析可以知道是因为我们的task没有在原来的依赖链中,解决方法就是把它加到原有的依赖链中!方法如下:

//配置检查完后
afterEvaluate {
    logger.log(LogLevel.ERROR, assemble.getTaskDependencies().toString())
    logger.log(LogLevel.ERROR, assemble.getTaskDependencies().getDependencies().toString())
    //让打包任务先依赖assemble任务
    def t = tasks.jarAopLib
    t.dependsOn assemble.getTaskDependencies().getDependencies()
    //让assemble任务再依赖jarAopLib,这样相当于在原有任务中插入任务jarAopLib
    assemble.dependsOn t
}

//打包任务
task jarAopLib(type: Jar) {
    archiveName = 'aop.jar'
    from('build/intermediates/classes/release')
    destinationDir = file('build/libs')
//    into('build/libs')
    exclude('org/cmdmac/aop/BuildConfig.class')
    exclude('org/cmdmac/aop/BuildConfig\$*.class')
    exclude('**/R.class')
    exclude('**/R\$*.class')
    include('org/cmdmac/aop/')
}

重写afterEvalute闭包(这是gradle配置完成后会调用的方法,gradle分配置task和运行task两个状态),修改原来的依赖关系,把自定义的task加入到依赖链中,此时点run会自动执行jarAopLib生成一个aop.jar文件在工程的build/libs下。


方法其实很简单,关键的是要了解熟悉gradle的机制还有gradle众多task类型以前相关的api,这个就得到gradle.com官网去学习才行了,比如就得知道要在afterEvaluate这里修改依赖关系,否则无从下手,另外得知道getTaskDependencies().getDependencies()函数的用法,这两个方法定义的其实有点奇怪的,也是试了多次才成功。

上面我们是把打包任务定义在外层,这种方式不能根据debug和release分开打包,其实也可以把任务定义在闭包里面根据variant的根据来实现分类型打包,如:

afterEvaluate {
    //遍历编译类型,一般是debug和release两种,用android.libraryVariants是因为我写在Library工程
    android.libraryVariants.each { variant ->
        //tasks对象包含了project下的所有task。这里根据编译类型实现命名不同动态创建task
        def t = tasks.create(name: "JarLibTask-${variant.name}", type: Jar) {
            archiveName  "aop-${variant.name}.jar"
            from('build/intermediates/classes/release')
            destinationDir = file('build/libs')
            exclude('org/cmdmac/aop/BuildConfig.class')
            exclude('org/cmdmac/aop/BuildConfig\$*.class')
            exclude('**/R.class')
            exclude('**/R\$*.class')
            include('org/cmdmac/aop/')
        }
        t.doLast {
            //打包完成时会执行
            System.out.println('打包完啦');
        }
        //修改依赖关系
        t.dependsOn assemble.getTaskDependencies().getDependencies()
        assemble.dependsOn t
    }
}
点run就会出现aop-debug.jar和aop-release.jar,怎么样,是不是挺好用的?

上面的task是动态创建的,创建task方式有挺多种,我自己总结了这么几种使用方式:

//用task带括号创建要注意,第一个参数不能name:'xxx',否则参数无效,变成一个匿名task
//匿名task,archiveName属性不生效
 def t = task("ttt${variant.name}", type: Jar) {
            archiveName  "aop-${variant.name}.jar"
            logger.log(LogLevel.ERROR, 'ttt')
        }
//有效,第一个参数为task名称
 def t = task("ttt${variant.name}", type: Jar) {
            logger.log(LogLevel.ERROR, 'ttt')
        }
//也有效,第一个参数为task名称
 def t = task(name: "ttt${variant.name}", type: Jar) {
            logger.log(LogLevel.ERROR, 'ttt')
        }
//也可以用tasks内置对象来创建
def t = tasks.create(name: 'xxx', type: Jar) {
	…
}
//也可以这样
def t = task name(type: Jar) {
	…
}

上面的例子中有看到可以在字符串中动态填入参数的用法,有点像java的String.format功能,这里需要注意的是groovy中要使用这个功能字符串需要使用双引号,单引号只是单纯的字符串,如:

//要用双引号才能字符串内带计算,单引号是纯字符串,下面这句输出结果为:'${variant.name      
  logger.log(LogLevel.ERROR, '${variant.name}')
总结 
gradle的task很强大,要学会gradle实现自定义的功能需要多学习gradle插件中实现的api和task类型等等知识
### 打包非可执行 JAR 文件 尽管 Spring Boot 提供了一种简单的方式来创建可执行的 JAR 文件,但在某些情况下可能需要打包一个非可执行的 JAR 文件。通过 Gradle 构建工具可以轻松实现这一目标。 为了构建非可执行的 JAR 文件,在 `build.gradle` 文件中可以通过调整插件配置以及任务设置来完成此操作。默认情况下,Spring Boot 的 Gradle 插件会自动将项目构建成可执行的 JAR 文件。然而,禁用该功能并生成普通的 JAR 文件是可行的[^1]。 以下是具体的解决方案: #### 修改 build.gradle 配置 在项目的 `build.gradle` 文件中,移除或禁用 Spring Boot 的特定行为以防止其生成可执行 JAR 文件。具体来说,可以通过以下方式实现: ```groovy plugins { id 'java' id 'org.springframework.boot' version '3.0.0' apply false // 禁用自动应用插件 } jar { enabled = true // 启用标准 JAR 打包任务 } ``` 上述代码片段中的关键部分在于设置了 `enabled = true` 来启用标准的 JAR 任务,并且显式地关闭了 Spring Boot 自动应用的功能 (`apply false`)。这样能够确保最终产物是一个不带启动脚本或其他附加元数据的纯 JAR 文件[^2]。 #### 调整依赖范围 如果仅需发布库而不需要运行时支持,则应考虑更改依赖关系声明的方式。例如,对于测试环境下的依赖项,应该标记为 `testImplementation` 或者其他类似的限定词;而对于那些只用于编译阶段而非实际部署场景里的组件则设成 `compileOnly` 类型。 另外需要注意的是,当切换至生产模式下进行分发前,请务必确认所有必要的第三方模块均已正确引入到最终制品当中去[^3]。 ```groovy dependencies { implementation 'org.springframework:spring-core' testImplementation 'junit:junit:4.13.2' compileOnly 'javax.servlet:javax.servlet-api:4.0.1' } ``` 以上展示了如何定义不同类型的需求集合以便更好地管理整个工程结构及其关联资源。 ### 结论 综上所述,虽然 Spring Boot 默认倾向于制作自包容式的应用程序容器形式即所谓的“fat jar”,但我们仍然有能力定制化自己的构建流程从而得到传统意义上的不可执行版本档案文件——只需合理配置好对应的构建描述文档(build script),就能满足相应需求[^1]^。 ```python print("成功生成非可执行JAR") ``` 相关问题
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值