前言 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
命令一样。示例带入如下:
1 2 3 4 5 6 7 getAllprojects().eachWithIndex { Project entry, int i -> if (i == 0 ) { println("RootProject-------${entry.name}" ) } else { println("SubProject-------${entry.name}" ) } }
输出结果如下:
1 2 3 4 RootProject-------APMProjetct SubProject-------apm SubProject-------app SubProject-------aspectj
getSubprojects() 此方法是获取所有子工程的实例,示例代码如下:
1 2 3 getSubprojects().eachWithIndex { Project entry, int i -> println("SubProject-------${entry.name}" ) }
输出结果如下:
1 2 3 4 > Configure project : SubProject-------apm SubProject-------app SubProject-------aspectj
getRootProject() 既然我们可以拿到所有的子节点,那我们依然可以单独获取到根节点,示例代码如下:
1 println ("the root project name is ${getRootProject().name}" )
输出结果如下:
1 2 > Configure project : the root project name is APMProjetct
getParent() 此方法是用于在子工程获取父工程的实例,示例代码如下:
1 println ("the parent project name is ${getParent().name}" )
输出结果可想而知:
1 2 > Configure project :aspectj the parent project name is APMProjetct
projects() project是为了让我们在父工程的build.gradle文件,针对子project做一些单独的处理,比如这样:
1 2 3 project ("app" ) { apply plugin: 'com.android.application' }
allprojects() allprojects 表示用于配置当前 project 及其每一个子 project,在 allprojects 中我们一般用来配置一些通用的配置,比如最常见的全局仓库配置。
1 2 3 4 5 6 allprojects { repositories { google () jcenter () } }
subprojects() 此方法是为了让我们对所有的子project做一些配置,比如这样:
1 2 3 4 5 subprojects { if (project .plugins.hasPlugin("com.android.library" )){ apply from "../uploadMaven.gradle" } }
ext扩展属性 我们可以通过ext扩展属性默认修改其他工程build.gradle的文件配置。比如我在root project中新增了如下属性:
1 2 3 4 ext { minSdkVersion = 21 targetSdkVersion = 30 }
那么我们可以在子工程的build.gralde文件修改文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 android { compileSdkVersion 30 buildToolsVersion "30.0.1" defaultConfig { applicationId "com.xxxxx.apmprojetct" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } }
另外我们还可以通过apply的形式依赖自己新增的gradle文件,比如我们可以新增一个config.gradle文件,具体内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 android { signingConfigs { debug { storeFile file('xxx.jks' ) storePassword 'xxx' keyAlias 'xxxx' keyPassword 'xxxx' v1SigningEnabled true v2SigningEnabled true } release { storeFile file('xxx.jks' ) storePassword 'xxx' keyAlias 'xxxx' keyPassword 'xxx' v1SigningEnabled true v2SigningEnabled true } } }
那么我们可以在工程中这样使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 apply from: 'config.gradle' android { buildTypes { debug { signingConfig signingConfigs.debug minifyEnabled false shrinkResources false proguardFiles getDefaultProguardFile('proguard-android.txt' ), 'proguard-rules.pro' versionNameSuffix "_dev" } release { signingConfig signingConfigs.release minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt' ), 'proguard-rules.pro' } } }
gradle文件操作 gradle中操作本地文件可以使用的是Project.file()方法,通过指定文件的相对路径或者绝对路径来进行操作。比如我们可以新建一个文件,可以查看一个文件的绝对路径,也可以判断一个文件是否存在,示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 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())
同步一下,输出结果如下:
1 2 /Users/ xxx/xxx/ src/main/ java/test.javatrue
文件集合 Gradle中文件集合就是类似于java中的数组,Gradle中使用FileCollection接口表示,我们可以使用Project.files()方法来获得一个文件集合对象,所有文件集合都是用到的时候才会创建。示例代码如下:
1 2 3 FileCollection collection = files('src/test1.txt' , new File('src/test2.txt' ), ['src/test3.txt' , 'src/test4.txt' ])
我们可以这样遍历文件:
1 2 3 4 collection.each { File file -> println file.name }
我们还可以这样转换文件:
1 2 3 4 5 6 7 8 9 10 Set set1 = collection.files Set set2 = collection as Set List list = collection as List String path = collection.asPath File file1 = collection.singleFile File file2 = collection as File
除此之外,我们还可以新增或者删除一个文件,比如这样:
1 2 3 def union = collection + files('src/test5.txt' )def different = collection - files('src/test3.txt' )
文件树 文件树你可以理解成是一个有层级结构的文件集合,所以文件树中包含了所有文件集合的操作。我们可以使用Project.fileTree()方法来创建文件树对象,还可以使用过虑条件来包含或排除相关文件。示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 FileTree tree = fileTree(dir: 'src/main' ) tree.include '**/*.java' tree.exclude '**/Abstract*' tree = fileTree('src' ).include('**/*.java' ) tree = fileTree('src' ) { include '**/*.java' } tree = fileTree(dir: 'src' , include: '**/*.java' ) tree = fileTree(dir: 'src' , includes: ['**/*.java' , '**/*.xml' ]) tree = fileTree(dir: 'src' , include: '**/*.java' , exclude: '**/*test*/**' )
既然说到了文件树的创建,当然,我们也可以对文件树进行一些业务操作,比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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目录,那我们可以这样做:
1 2 3 4 task copyTask(type: Copy) { from 'src/main/java/fileA' into 'src/main/kotlin/fileB' }
当然,我们也是支持批量copy的,比如这样:
1 2 3 4 5 6 7 8 9 10 task copyTask(type: Copy) { from 'src/main/java' from 'src/main/res/index.html' from zipTree('src/main/assets.zip' ) into 'src/main/mouble' }
前面我们也说了,我们可以在copy的时候进行重命名,最常见的场景,就是项目拆解模块的时候,我们需要重新命名,那我们可以这样操作:
1 2 3 4 5 6 7 8 task rename(type: Copy) { from 'moudleA/src/main/res/' into 'moudleB/src/main/res/' rename { String fileName -> fileName.replace('moudleA' , 'moudleB' ) } }
大量的节约了手动重命名的成本。 同样我们也可以新增过滤条件:
1 2 3 4 5 6 7 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' ) } }
当然我们还可以拷贝的同时,并删除对应目录文件,我们可以这么操作:
1 2 3 4 5 task libs(type: Sync) { from configurations.runtime into "$buildDir/libs" }
总结 本文我们简单的介绍了projects的相关操作以及在gradle中我们如何去操作文件,当然,gradle中除了projects,还有一个核心的task,这个我们放在下一节进行介绍。
参考 暴力突破 Gradle 自动化项目构建(五)- Gradle 核心之 Project gradle操作文件详解