上一節咱們探討了project中project類中的幾個api,經過這幾個api咱們能夠看到,咱們一個project中全部的project並非獨立存在的而是相互關聯的,咱們能夠對對工程進行遍歷獲得每一個project,或者是project的路徑獲得對應的project。java
首先先問幾個問題?
①爲何每一個module下都有一個build.gradle文件?
②爲何默認模式下打包生成的文件在一個叫build的文件夾下?
③爲何會存在gradle.properties文件?android
看完本文後,你就能解答出上面的幾個問題了
不要打我,先上一段代碼git
@HasInternalProtocol
public interface Project extends Comparable<Project>, ExtensionAware, PluginAware {
/** * The default project build file name. */
String DEFAULT_BUILD_FILE = "build.gradle";
/** * The hierarchy separator for project and task path names. */
String PATH_SEPARATOR = ":";
/** * The default build directory name. */
String DEFAULT_BUILD_DIR_NAME = "build";
String GRADLE_PROPERTIES = "gradle.properties";
String SYSTEM_PROP_PREFIX = "systemProp";
String DEFAULT_VERSION = "unspecified";
String DEFAULT_STATUS = "release";
…………
}
複製代碼
既然咱們要學習Project的相關知識,那麼咱們先要了解下Project這個類裏面到底有什麼東西,上面的代碼我列舉了一部分,可是這一部分的內容已經能夠解答上面的問題了。github
DEFAULT_BUILD_FILE:咱們的project默認就是從這個文件中讀取相關配置,而後對它本身進行初始化配置
PATH_SEPARATOR:文件分隔符,在Mac系統中,文件分隔符是反斜槓"\",而在gradle文件中,分隔符都是用冒號(不區分系統)
DEFAULT_BUILD_DIR_NAME:默認生成的build文件
GRADLE_PROPERTIES:姑且稱爲自定義屬性文件
複製代碼
簡單對Project文件中的屬性瞭解後,開始咱們今天的新內容,Project在爲咱們提供了便利的屬的同時也支持開發者對其進行擴展的操做,這樣就能知足咱們各類各樣的構建需求了。如今開始進行咱們的擴展之路。
在開始擴展以前咱們先來看一個代碼片斷。經過該片斷開始咱們的擴展之旅。api
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.lcf.demo"
minSdkVersion 17
targetSdkVersion 28
versionCode 32
}
}
dependencies {
api fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support:support-v4:28.0.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'
}
複製代碼
之前我老是把build.gradle文件當作是一個配置文件,就至關於一個Maven或者Ant同樣,在這個配置文件中直接寫數值或者字符串是沒有問題的,可是在學習了gradle,瞭解它是一個變成框架之後再後將build.gradle文件當成是一個類再來看的時候,這樣寫代碼的方式真的有點low。 這種寫法也被稱之爲魔術數(魔術數字是程式設計中所謂的直接寫在程式碼裏的具體數值,如「10」「123」等以數字直接寫出的值),那麼這樣看的話咱們這個類中有大量的無用的字符串或者是數值,那麼如何解決這個問題呢?
方法一:定義變量閉包
apply plugin: 'com.android.application'
def mCompileSdkVersion=28
def libCompat='com.android.support:appcompat-v7:28.0.0'
android {
compileSdkVersion mCompileSdkVersion
defaultConfig {
applicationId "com.lcf.demo"
minSdkVersion 17
targetSdkVersion 28
versionCode 32
}
}
dependencies {
api fileTree(include: ['*.jar'], dir: 'libs')
implementation libCompat
implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support:support-v4:28.0.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'
}
複製代碼
經過這種方式咱們能夠將全部的常量轉變爲有意義的變量,固然gradle是支持擴展操做的,那麼咱們能夠將代碼改爲以下形式:app
apply plugin: 'com.android.application'
ext{
mCompileSdkVersion=28
libCompat='com.android.support:appcompat-v7:28.0.0'
}
android {
compileSdkVersion this.mCompileSdkVersion
defaultConfig {
applicationId "com.lcf.demo"
minSdkVersion 17
targetSdkVersion 28
versionCode 32
}
}
dependencies {
api fileTree(include: ['*.jar'], dir: 'libs')
implementation this.libCompat
implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support:support-v4:28.0.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'
}
複製代碼
就這樣咱們經過ext這個關鍵字實現了擴展屬性的操做,比較上面的代碼,可能你會說,這也沒有什麼優點,就是代碼改動了下位置,還多寫了一部分呢?框架
且先莫急,的確,若是放在一個project下面,這種擴展的寫法的確沒有什麼優點,可是你們想一想,一個正常的項目是不可能只有一個project的,舉個栗子,若是你的項目有5個project,而你採用的就是常量的寫法,這個時候須要你修改的話,你就須要這5個類的每一處都須要改動,並且一個不當心的話,都有可能改錯,或者加載lib失敗。maven
這個時候你或許會說,就算是這樣,那我不仍是要改5個project中的ext閉包中的屬性嗎?
莫慌莫慌~,此時你還記得咱們上一節中的getAllProjects和getSubprojects屬性嗎?學習
咱們能夠按照上節的內容來改造下,來來來,讓咱們蕩起雙槳,呸,讓咱們將代碼擼起來,首先找到項目根工程的project文件
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.1'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
}
}
allprojects {
repositories {
jcenter()
google()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
subprojects{
ext{
mCompileSdkVersion=28
libCompat='com.android.support:appcompat-v7:28.0.0'
}
}
複製代碼
此時咱們將以前在project中寫好的ext擴展刪除
apply plugin: 'com.android.application'
android {
compileSdkVersion this.mCompileSdkVersion
defaultConfig {
applicationId "com.lcf.demo"
minSdkVersion 17
targetSdkVersion 28
versionCode 32
}
}
dependencies {
api fileTree(include: ['*.jar'], dir: 'libs')
implementation this.libCompat
implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support:support-v4:28.0.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'
}
複製代碼
而後咱們編譯下項目,驗證下這種寫法是否有效,通過編譯後發現,這樣的寫法是對的,咱們能成功使用在根工程中project定義subprojects中定義的ext爲全部的子project添加配置屬性,簡直堪稱完美。
本着對代碼要求完美的心,說白了就是不做就不會死的心,還能不能把代碼寫的更好一點呢?上面的代碼看似很完美,可是實際上是不完美的。
雖然咱們上面的代碼只寫了一次,只定義了一次,可是咱們的gradle會給每個子project都定義一次ext這個擴展屬性,因此從本質上來講,咱們的每個project仍是定義了一個ext的擴展屬性,只不過如今的過程是由gradle幫咱們進行了操做。
上節課咱們說到getAllProjects,也就是在根工程中進行操做,子Project中全部屬性都會繼承父Project中的屬性,那麼咱們的代碼又能夠改爲下面的形式:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.1'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
}
}
allprojects {
repositories {
jcenter()
google()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
ext{
mCompileSdkVersion=28
libCompat='com.android.support:appcompat-v7:28.0.0'
}
複製代碼
apply plugin: 'com.android.application'
android {
compileSdkVersion this.rootProject.mCompileSdkVersion
defaultConfig {
applicationId "com.lcf.demo"
minSdkVersion 17
targetSdkVersion 28
versionCode 32
}
}
dependencies {
api fileTree(include: ['*.jar'], dir: 'libs')
implementation this.rootProject.libCompat
implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support:support-v4:28.0.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'
}
複製代碼
到此時,咱們的代碼更改的更優了,可是還不是最優的,(OS:真™墨跡啊,就不能直接講講最優的嘛),其實講了這麼多,基本上都是你們常見的寫法,說白了就是記錄一個踩坑的過程。
重頭戲來了,最優解決方案 不知道你們是否還記得上一節中有稍微提到的maven配置加載的內容
apply from:'../publishToMaven.gradle'
複製代碼
publishToMaven.gradle這個文件上節咱們就說了,存放的是maven配置相關的內容,其實咱們的最優方案就是和這個同樣,自定義一個configs.gradle的文件,將全部的變量放到這個裏面。
ext{
android=[
applicationId :"com.lcf.demo"
minSdkVersion :17
targetSdkVersion :28
versionCode :32
]
signConfigs=[
]
java=[
]
dependence=[
'design': 'com.android.support:design:28.0.0'
'support-v4': 'com.android.support:support-v4:28.0.0'
'recyclerview': 'com.android.support:recyclerview-v7:28.0.0'
]
}
複製代碼
上面的代碼按照了正真的build文件中使用的分組格式進行分組,這樣定義讓咱們的分類更合理,讓咱們的在每一個分組中都是用Map的key、value的形式定義的,在定義好這個文件後,咱們只須要在根工程中引用便可。
apply from: this.file('configs.gradle')
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.1'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
}
}
allprojects {
repositories {
jcenter()
google()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
複製代碼
在根工程這引用後,咱們就能夠在子工程中使用了,且看以下代碼:
apply plugin: 'com.android.application'
android {
compileSdkVersion this.mCompileSdkVersion
defaultConfig {
applicationId rootProjet.ext.android.applicationId
minSdkVersion rootProjet.ext.android.minSdkVersion
targetSdkVersion rootProjet.ext.android.targetSdkVersion
versionCode rootProjet.ext.android.versionCode
}
}
dependencies {
compile rootProjet.ext.dependence.design
compile rootProjet.ext.dependence.support-v4
compile rootProjet.ext.dependence.recyclerview
}
複製代碼
通過上面的一番操做,如今咱們的gradle文件中幾乎已經看不到字符串常量和int類型的常量了,並且你不以爲代碼更加整潔了嗎?而且修改起來,也只須要維護configs文件就行了。 到這裏,第一種擴展屬性的方式就介紹完了,下面開始咱們的第二種方式。 還記得前面說的gradle.properties文件嗎?對,這種方式就是用到他自身的這個文件,可是要記住,這個文件中的屬性只能用key:value的形式,切忌用Map操做,好比咱們要經過屬性加載模塊
isDebug=false
mCompileSdkVersion=25
複製代碼
在setting文件中操做以下:
//include ':Test'
//如今經過isDebug屬性來肯定是否加載該模塊
if(hasProperty('isDebug')?isDebug.toBoolean():false){
include ':Test'
}
複製代碼
此時,咱們編譯下項目,能夠在看到Test項目已經再也不是lib工程了,沒有lib標識的小圖標了,isDebug=true的時候就是lib了,注意,在這個文件中自定義中屬性不能和已有的gradle的屬性的名稱一致,而且在使用的時候須要轉換成對應的類型,不然會沒法使用,好比要使用mCompileSdkVersion這個屬性,咱們就要寫成這樣
compileSdkVersion mCompileSdkVersion.toInteger()
複製代碼
囉裏囉嗦這麼多,總算是將這兩種加載擴展方式的方法說完了,下面小結一下。在小結以前,咱們仍是解答下開篇的問題,其實答案很簡單,就是由於Project自身屬性的內容決定如此(我認爲是這樣的,若是你有更好的回答歡迎留言告訴我)。
最後想說一句,gradle是真心的強大,大家以爲呢?