Gradle核心之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 = 21
targetSdkVersion = 30
}
那麼我們可以在子工程的build.gralde檔案修改檔案如下:
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檔案,具體內容如下:
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
}
}
}
那麼我們可以在工程中這樣使用:
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()方法,通過指定檔案的相對路徑或者絕對路徑來進行操作。比如我們可以新建一個檔案,可以檢視一個檔案的絕對路徑,也可以判斷一個檔案是否存在,示例程式碼如下:
// 使用相對路徑
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
更多文章請關注我的公眾號:碼農職場