热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

深入解析Gradle中的Project核心组件

在Gradle构建系统中,`Project`是一个核心组件,扮演着至关重要的角色。通过使用`./gradlewprojects`命令,可以清晰地列出当前项目结构中包含的所有子项目,这有助于开发者更好地理解和管理复杂的多模块项目。此外,`Project`对象还提供了丰富的配置选项和生命周期管理功能,使得构建过程更加灵活高效。

前言

project在gradle里起到里重要的作用,上节我们也说过可以通过./gradlew projects打印当前项目下所有的project,准确的说是有build.gradle的文件既是一个project。而有多少project取决于在setting.gradle文件中设置了多少个。一个project对应一个输出,而具体输出什么取决于build.gradle里面的内容。

Project核心API

每个工程下都有一个build.gradle文件。根目录的build.gradle可以管理子工程下面的build.gradle。下面具体看下project相关api。

getAllProjects()

我们可以通过getAllprojects打印出所有的project,可以理解成和./gradlew projects命令一样。示例带入如下:

getAllprojects().eachWithIndex { Project entry, int i ->if (i == 0) {println("RootProject-------${entry.name}")} else {println("SubProject-------${entry.name}")}
}

输出结果如下:

RootProject-------APMProjetct
SubProject-------apm
SubProject-------app
SubProject-------aspectj

getSubprojects()

此方法是获取所有子工程的实例,示例代码如下:

getSubprojects().eachWithIndex { Project entry, int i ->println("SubProject-------${entry.name}")
}

输出结果如下:

> Configure project :
SubProject-------apm
SubProject-------app
SubProject-------aspectj

getRootProject()

既然我们可以拿到所有的子节点,那我们依然可以单独获取到根节点,示例代码如下:

println("the root project name is ${getRootProject().name}")

输出结果如下:

> Configure project :
the root project name is APMProjetct

getParent()

此方法是用于在子工程获取父工程的实例,示例代码如下:

println("the parent project name is ${getParent().name}")

输出结果可想而知:

> Configure project :aspectj
the parent project name is APMProjetct

projects()

project是为了让我们在父工程的build.gradle文件,针对子project做一些单独的处理,比如这样:

project("app") {apply plugin: 'com.android.application'
}

allprojects()

allprojects 表示用于配置当前 project 及其每一个子 project,在 allprojects 中我们一般用来配置一些通用的配置,比如最常见的全局仓库配置。

allprojects {repositories {google()jcenter()}
}

subprojects()

此方法是为了让我们对所有的子project做一些配置,比如这样:

subprojects {if(project.plugins.hasPlugin("com.android.library")){apply from "../uploadMaven.gradle"}
}

ext扩展属性

我们可以通过ext扩展属性默认修改其他工程build.gradle的文件配置。比如我在root project中新增了如下属性:

ext {minSdkVersion = 21targetSdkVersion = 30
}

那么我们可以在子工程的build.gralde文件修改文件如下:

android {compileSdkVersion 30buildToolsVersion "30.0.1"defaultConfig {applicationId "com.xxxxx.apmprojetct"minSdkVersion rootProject.ext.minSdkVersiontargetSdkVersion rootProject.ext.targetSdkVersionversionCode 1versionName "1.0"testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"}
}

另外我们还可以通过apply的形式依赖自己新增的gradle文件,比如我们可以新增一个config.gradle文件,具体内容如下:

android {signingConfigs {debug {storeFile file('xxx.jks')storePassword 'xxx'keyAlias 'xxxx'keyPassword 'xxxx'v1SigningEnabled truev2SigningEnabled true}release {storeFile file('xxx.jks')storePassword 'xxx'keyAlias 'xxxx'keyPassword 'xxx'v1SigningEnabled truev2SigningEnabled true}}
}

那么我们可以在工程中这样使用:

apply from: 'config.gradle'
android {buildTypes {debug {signingConfig signingConfigs.debugminifyEnabled falseshrinkResources falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'versionNameSuffix "_dev"}release {signingConfig signingConfigs.releaseminifyEnabled trueshrinkResources trueproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}}
}

gradle文件操作

gradle中操作本地文件可以使用的是Project.file()方法,通过指定文件的相对路径或者绝对路径来进行操作。比如我们可以新建一个文件,可以查看一个文件的绝对路径,也可以判断一个文件是否存在,示例代码如下:

// 使用相对路径
File configFile = file('src/main/java/test.java')
configFile.createNewFile();// 使用绝对路径
configFile = file(/Users/xxx/xxx/src/main/java/test.java’)
println(configFile.absolutePath)// 使用一个文件对象
configFile = file(new File('src/main/java/test.java'))
// 打印文件是否存在
println(configFile.exists())

同步一下,输出结果如下:

/Users/xxx/xxx/src/main/java/test.java
true

文件集合

Gradle中文件集合就是类似于java中的数组,Gradle中使用FileCollection接口表示,我们可以使用Project.files()方法来获得一个文件集合对象,所有文件集合都是用到的时候才会创建。示例代码如下:

FileCollection collection = files('src/test1.txt',new File('src/test2.txt'),['src/test3.txt', 'src/test4.txt'])

我们可以这样遍历文件:

// 遍历所有集合
collection.each { File file ->println file.name
}

我们还可以这样转换文件:

// 把文件集合转换为Set类型
Set set1 = collection.files
Set set2 = collection as Set
// 把文件集合转换为List类型
List list = collection as List
// 把文件集合转换为String类型
String path = collection.asPath
// 把文件集合转换为File类型
File file1 = collection.singleFile
File file2 = collection as File

除此之外,我们还可以新增或者删除一个文件,比如这样:

// 添加或者删除一个集合
def union = collection + files('src/test5.txt')
def different = collection - files('src/test3.txt')

文件树

文件树你可以理解成是一个有层级结构的文件集合,所以文件树中包含了所有文件集合的操作。我们可以使用Project.fileTree()方法来创建文件树对象,还可以使用过虑条件来包含或排除相关文件。示例代码如下:

// 指定目录创建文件树对象
FileTree tree = fileTree(dir: 'src/main')// 给文件树对象添加包含指定文件
tree.include '**/*.java'
// 给文件树对象添加排除指定文件
tree.exclude '**/Abstract*'// 使用路径创建文件树对象,同时指定包含的文件
tree = fileTree('src').include('**/*.java')// 通过闭包创建文件树
tree = fileTree('src') {include '**/*.java'
}// 通过map创建文件树
tree = fileTree(dir: 'src', include: '**/*.java')
tree = fileTree(dir: 'src', includes: ['**/*.java', '**/*.xml'])
tree = fileTree(dir: 'src', include: '**/*.java', exclude: '**/*test*/**')

既然说到了文件树的创建,当然,我们也可以对文件树进行一些业务操作,比如:

// 遍历文件树的所有文件
tree.each {File file ->println file
}// 过虑生成新的文件树对象
FileTree filtered = tree.matching {include 'org/gradle/api/**'
}// 使用“+”号合并两个文件树,同文件集合的“+”操作一样
FileTree sum = tree + fileTree(dir: 'src/test')// 访问文件树中各项内容
tree.visit {element ->println "$element.relativePath => $element.file"
}

文件拷贝

我们可以通过copy的task对文件进行copy动作,并且可以指定copy内容和过滤copy内容,还可以在copy的过程中对文件进行重命名操作,先来个简单的,比如我需要从A目录copy到B目录,那我们可以这样做:

task copyTask(type: Copy) {from 'src/main/java/fileA'into 'src/main/kotlin/fileB'
}

当然,我们也是支持批量copy的,比如这样:

task copyTask(type: Copy) {// 拷贝src/main/webapp目录下所有的文件from 'src/main/java'// 拷贝单独的一个文件from 'src/main/res/index.html'// 从Zip压缩文件中拷贝内容from zipTree('src/main/assets.zip')// 拷贝到的目标目录into 'src/main/mouble'
}

前面我们也说了,我们可以在copy的时候进行重命名,最常见的场景,就是项目拆解模块的时候,我们需要重新命名,那我们可以这样操作:

task rename(type: Copy) {from 'moudleA/src/main/res/'into 'moudleB/src/main/res/'// 使用一个闭包方式重命名文件rename { String fileName ->fileName.replace('moudleA', 'moudleB')}
}

大量的节约了手动重命名的成本。
同样我们也可以新增过滤条件:

task copyTaskWithPatterns(type: Copy) {from 'src/main/drawable'into 'src/main/drawable-xxhdpi'include '*.jpg'exclude { details -> details.file.name.endsWith('.png') &&details.file.text.contains('.webp') }
}

当然我们还可以拷贝的同时,并删除对应目录文件,我们可以这么操作:

task libs(type: Sync) {from configurations.runtime// 拷贝之前会把$buildDir/libs目录下所有的清除into "$buildDir/libs"
}

总结

本文我们简单的介绍了projects的相关操作以及在gradle中我们如何去操作文件,当然,gradle中除了projects,还有一个核心的task,这个我们放在下一节进行介绍。

参考

暴力突破 Gradle 自动化项目构建(五)- Gradle 核心之 Project
gradle操作文件详解

本文首发于我的个人博客:Gradle核心之Project

更多文章请关注我的公众号:码农职场
在这里插入图片描述


推荐阅读
  • 深入理解Spark框架:RDD核心概念与操作详解
    RDD是Spark框架的核心计算模型,全称为弹性分布式数据集(Resilient Distributed Dataset)。本文详细解析了RDD的基本概念、特性及其在Spark中的关键操作,包括创建、转换和行动操作等,帮助读者深入理解Spark的工作原理和优化策略。通过具体示例和代码片段,进一步阐述了如何高效利用RDD进行大数据处理。 ... [详细]
  • Go语言实现Redis客户端与服务器的交互机制深入解析
    在前文对Godis v1.0版本的基础功能进行了详细介绍后,本文将重点探讨如何实现客户端与服务器之间的交互机制。通过具体代码实现,使客户端与服务器能够顺利通信,赋予项目实际运行的能力。本文将详细解析Go语言在实现这一过程中的关键技术和实现细节,帮助读者深入了解Redis客户端与服务器的交互原理。 ... [详细]
  • APKAnalyzer(1):命令行操作体验与功能解析
    在对apkChecker进行深入研究后,自然而然地关注到了Android Studio中的APK分析功能。将APK文件导入IDE中,系统会自动解析并展示其中各类文件的详细信息。官方文档提供了详细的命令行工具使用指南,帮助开发者快速上手。本文以一个RecyclerView的Adapter代理开源库为例,探讨了如何利用这些工具进行高效的APK分析。 ... [详细]
  • 进程(Process)是指计算机中程序对特定数据集的一次运行活动,是系统资源分配与调度的核心单元,构成了操作系统架构的基础。在早期以进程为中心的计算机体系结构中,进程被视为程序的执行实例,其状态和控制信息通过任务描述符(task_struct)进行管理和维护。本文将深入探讨进程的概念及其关键数据结构task_struct,解析其在操作系统中的作用和实现机制。 ... [详细]
  • C#编程指南:实现列表与WPF数据网格的高效绑定方法 ... [详细]
  • 深入解析Tomcat:开发者的实用指南
    深入解析Tomcat:开发者的实用指南 ... [详细]
  • 可转债数据智能抓取与分析平台优化
    本项目旨在优化可转债数据的智能抓取与分析平台。通过爬取集思录上的可转债信息(排除已发布赎回的债券),并结合安道全教授提出的三条安全线投资策略,新增了建仓线、加仓线和重仓线,以提供更精准的投资建议。 ... [详细]
  • 为了优化直播应用底部聊天框的弹出机制,确保在不同设备上的布局稳定性和兼容性,特别是在配备虚拟按键的设备上,我们对用户交互流程进行了调整。首次打开应用时,需先点击首个输入框以准确获取键盘高度,避免直接点击第二个输入框导致的整体布局挤压问题。此优化通过调整 `activity_main.xml` 布局文件实现,确保了更好的用户体验和界面适配。 ... [详细]
  • 深入解析Spring Boot自动配置机制及其核心原理
    Spring Boot 的自动配置机制是其核心特性之一,旨在简化开发过程并提高效率。本文将深入探讨这一机制的工作原理,解释其如何通过智能化的类路径扫描和条件注解实现自动装配。通过对 Spring Boot 自动配置的详细解析,读者将能够更好地理解和应用这一强大功能,从而在实际项目中更加高效地利用 Spring Boot。 ... [详细]
  • 技术日志:深入探讨Spark Streaming与Spark SQL的融合应用
    技术日志:深入探讨Spark Streaming与Spark SQL的融合应用 ... [详细]
  • 深入解析:RKHunter与AIDE在入侵检测中的应用与优势
    本文深入探讨了RKHunter与AIDE在入侵检测领域的应用及其独特优势。通过对比分析,详细阐述了这两种工具在系统完整性验证、恶意软件检测及日志文件监控等方面的技术特点和实际效果,为安全管理人员提供了有效的防护策略建议。 ... [详细]
  • Java 8 引入了 Stream API,这一新特性极大地增强了集合数据的处理能力。通过 Stream API,开发者可以更加高效、简洁地进行集合数据的遍历、过滤和转换操作。本文将详细解析 Stream API 的核心概念和常见用法,帮助读者更好地理解和应用这一强大的工具。 ... [详细]
  • 本文将介绍一种扩展的ASP.NET MVC三层架构框架,并通过使用StructureMap实现依赖注入,以降低代码间的耦合度。该方法不仅能够提高代码的可维护性和可测试性,还能增强系统的灵活性和扩展性。通过具体实践案例,详细阐述了如何在实际开发中有效应用这一技术。 ... [详细]
  • 第五章详细探讨了 Red Hat Enterprise Linux 6 中的 Ext3 文件系统。5.1 节介绍了如何创建 Ext3 文件系统,包括必要的命令和步骤,以及在实际操作中可能遇到的问题和解决方案。此外,还涵盖了 Ext3 文件系统的性能优化和维护技巧,为用户提供全面的操作指南。 ... [详细]
  • 本文探讨了将PEBuilder转换为DIBooter.sh的方法,重点介绍了如何将DI工具集成到启动层,实现离线镜像引导安装。通过使用DD命令替代传统的grub-install工具,实现了GRUB的离线安装。此外,还详细解析了bootice工具的工作原理及其在该过程中的应用,确保系统在无网络环境下也能顺利引导和安装。 ... [详细]
author-avatar
乐思GO_361
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有