Gradle 入門到精通(三)
前言
根據我們上一篇的介紹,我們知道了專案的結構以及構建的流程,根據上面的知識,我們知道了構建的規則實際就是我們寫在build.gradle的內容。gradle android外掛讀取這個檔案的內容後,最後完成構建工作。在講解實際內容前,我先提供一個網站給大家,因為gradle android 外掛 是通過dsl語言編寫的,所以我們需要知道在什麼地方獲取相應的api。
7 build.gradle檔案分析
第一個網站是gradle官方提供的dsl,第二個網站是google提供的dsl查詢手冊
7.1 根目錄的build.gradle檔案
我們來開啟根目錄下面的build.gradle檔案,這個檔案是整個專案的配置檔案,我們一般是放置一些基礎的配置。
上圖是build.gradle檔案的內容
7.1.1 buildscript
buildscript{} 這個是基礎配置,所有的子模組都會讀取到這個配置裡面的內容,當構建開始的時候,就開始讀取這個 buildscript{} 裡面的內容。
repositories{} 這個模組的內容告訴gradle 去什麼地址下載第三方的庫。
但是有一個問題就是上面的兩個網站在中國訪問速度慢
buildscript { repositories { maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'} } }
可以使用阿里雲的maven服務
7.1.2 allprojects
allprojects 一般是配置所有模組的共同使用的內容。
allprojects {
repositories {
jcenter()
}
}
這個是預設的配置,代表所有的子modle都是從jcenter獲取第三方包的。我建議大家可以改成下面的寫法
allprojects { repositories { maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'} } }
7.1.3 gradle外掛以及gradle版本的關係
在根目錄上面的build.gradle的版本我們可以設定gradle 外掛的版本號,初學者經常搞不懂外掛與gradle的關係。特別是個版本之間的關係,下面我們來講講外掛設定的方式。
最後的序號就是外掛的版本號,注意外掛不是gradle,外掛是根據gradle特性編寫為完成需求的jar包,外掛依賴於gradle。
dependencies {
classpath 'com.android.tools.build:gradle:2.3.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
如果你使用的是2.3版本的外掛,必須使用gradle3.3以上的版本。
如果你使用的是2.2版本的外掛,必須使用gradle2.14.1以上的版本。
基本原則就是對照上面的表,看看你使用的是什麼版本的外掛。
那gradle的版本設定在哪裡設定呢?我們開啟gradle資料夾找到gradle-wrapper.properties檔案,如下圖所示
最後我再介紹一個方法,經常有同學說開啟一個專案很久,其實就是去下載gradle.我們可以根據上面的這個表來手動下載gradle。然後放置到相應的資料夾內,下面的兩張圖片是外掛的檔案目錄和gradle的檔案目錄
7.2 子專案的build.gradle
一般在稍微大一點的專案中,我們都按照業務邏輯分好不同的模組。根目錄下的build.gradle是對所有模組起效果的基礎配置,而每個模組下的build.gradle是這個模組的詳細構建的配置,下面我們來學習一下有哪些內容。
上面的這張圖片是預設的build的內容。我們看到內容可以分成三份。
7.2.1 apply
apply plugin: 'com.android.application'
這句話告訴gradle使用什麼型別的外掛進行構建。上面的是構建應用的,如果是構建庫檔案的是有下面的
apply plugin: 'com.android.library'
7.2.2 dependencies{} 依賴配置
這個模組是宣告專案的依賴,為什麼我們要配置依賴呢?我們的專案大部分需要使用第三方庫,而第三庫很有可能還有其他的依賴,比如說Okhttp。這個依賴的內容由gradle進管理,免除了開發者下載、匯入、設定等繁瑣的炒作。這個內容不是android gradle 外掛提供了,是gradle提供的,也就是說不止android,java,c++,只要是使用gradle構建的專案都能夠使用這個模組宣告。
這個模組是宣告專案的依賴,可以依賴本地的檔案,遠端的資源庫,本地的library庫。詳細的引數我們可以查詢gradle Dsl的工具頁面。
如果英語好的同學可以看到,gradle支援了4種依賴的模式。
- compile 意思是告訴gradle編譯程式碼是需要使用的依賴。
- runtime 產品程式碼在執行時需要的依賴。
- testCompile 編譯測試程式碼時所需要的依賴。
- testRuntime 執行測試時需要的依賴。
其中 runtime會包括compile的依賴。 testRuntime會包括testCompile的依賴。但是很遺憾的是,android gradle plugings不支援runtime,所以android只包含上面的compile、testCompile兩種模式。
那為什麼會有兩種不一樣的模式了,其實是這樣的,比如在java Web中,編譯的時候需要的是servlet的依賴,但是執行的時候,就由伺服器的容器提供,所以需要分開來,但是在android中,基本上使用的依賴就是一起把類檔案編譯打包到apk,所以沒有runtime與compile的區別。
7.2.2.1 compile 編譯時匯入依賴
遠端依賴
compile是gradle依賴使用最多的關鍵字,在build.gradle中使用了compile後,gradle就會去repositories中載入,我們看看如果在我們的專案中使用了OKHTTP的寫法是怎麼寫的呢?
compile 'com.squareup.okhttp3:okhttp:3.8.0'
這個是最簡單的寫法,我們剛開始從eclipse轉到android studio開發的時候就知道整兒寫了,但是世界實際這個一個簡短的寫法。規範的寫法應用是這樣。
compile group: 'com.squareup.okhttp3', name: 'okhttp', version: '3.8.0'
同步完成後,我們可以在External Libraries下面找到新增的依賴
)
本地依賴
gradle 提供了下載遠端依賴包的能力,這個方式也是目前最流行的方式,但是考慮到國情等情況,我們也經常需要使用本地的jar包、AAR包、libery依賴。下面我們來學習這幾種依賴的寫法
本地jar包
compile fileTree(include: ['*.jar'], dir: 'libs')
上面這句話就把libs下面的jar包,匯入到專案中,也就是繫結到專案的classPath.也可以單獨制定某一個jar包。
compile files('libs/xxxx.jar')
上面的這兩種方法都是匯入jar包的方法,如果需要匯入aar包,我們需要按照下面的來寫。
本地aar包
repositories {
flatDir {
dirs 'libs'
}
}
增加一個本地的源目錄。將aar檔案放入libs資料夾。
compile(name: '不帶字尾的檔名', ext: 'aar')
同步完成後就可以使用匯入的類庫了。
library依賴
我們可以在專案中建立不同的module,建立的model的時候我們可以選擇建立一個不同的型別。
)
上圖是我們建立一個新的module的時候可以選擇的選項,通常我們選擇的是第一個,代表這個是一個可執行的專案。第二個程式碼是一個libery庫,它與一般的專案不同,libery專案不能執行,libery專案最後會生成一個aar包,aar包與jar包類似。jar包是將編譯的class打包的壓縮包,aar包不止包括了class還有專案的資源生成的壓縮包。
上面我們學習了怎麼依賴一個aar包,下面我們來學習一下怎麼依賴一個library專案,常見的有兩種方法:
1 編寫程式碼依賴
在需要依賴的模組上面的build.gradle檔案內,查詢到dependencies{}模組。新增以下程式碼:
compile project(':名稱')
在冒號後面輸入模組的名稱
2 ide新增依賴
我們在專案上面點選右鍵開啟moduleseting
7.2.3 android{} 構建詳細配置
android 模組的是該模組的詳細設定,android app 的大部分的構建的內容都是在這個模組內配置的。
android {
compileSdkVersion 24
buildToolsVersion "24.0.2"
defaultConfig {
applicationId "com.it520.x5webview"
minSdkVersion 15
targetSdkVersion 24
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
上面是android studio為我們建立的內容。
compileSdkVersion 24
告訴 Gradle 用哪個 Android SDK 版本編譯你的應用,建議使用最新的SDK 進行編譯。在現有程式碼上使用新的編譯檢查可以獲得很多好處,避免新棄用的 API ,並且為使用新的 API 做好準備。
buildToolsVersion "24.0.2"
構建工具的版本,其中包括了打包工具aapt、dx等等。這個工具的目錄位於..your_sdk_path/build-tools/XX.XX.XX,注意這個工具和gradle版本有關係。
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
buildTypes 用來設定應用的構建版本。預設的情況會建立兩個版本,1個版本是release(釋出版),1個版本是debug(開發版)。預設的情況下,只顯示了release的配置。我們一般都是在buildType中設定好相應的簽名檔案、打包加密方式、冗餘資源等。
上面的文件是buildType支援的所有的屬性
- applicationIdSuffix 包名的字尾
- versionNameSuffix 版本的字尾
上面兩個是我們在區分不同版本的時候增加的字尾名稱
- signingConfig
上面這個配置是設定打包的簽名
- shrinkResources
minifyEnabled
上面的配置是去除冗餘資源
defaultConfig {…}
預設配置,這裡的程式碼塊配置的在後面的各個構建變體(這裡理解成不同的版本)都能夠使用,這裡面設定的值,在不同的構建變體內還可以再修改成具體的值。
上面的配置是IDE預設生成的。瞭解預設的指令碼後,我們來看看詳細的配置。
7.2.3.1 簽名配置 SigningConfig
我們生成一個apk需要經過一個過程就是給這個app進行簽名的過程,這個過程我們要設定應用的簽名,有同學不明白,為啥咱們除錯的時候不需要?實際上預設提供了一個除錯的簽名檔案.在mac系統的位置在~/.android
在windows系統的位置在(C:\Documents and Settings[User Name].android)(C:\Users.android)這兩個位置中。我們可以看到一個檔案叫做debug.keystore。這個檔案就是我們的除錯的簽名檔案。
但是在正式包的時候,我們是不能使用除錯的簽名檔案的,我們需要使用對應的簽名檔案。
首先我們要生成一個簽名檔案,
生成完成後,我們要配置這個應用的簽名,配置簽名一般有以下幾個引數,詳細的引數請檢視
上圖的4個值分別是 簽名的別名,簽名的密碼,簽名的位置,簽名的密碼
signingConfigs {
debug {
}
realse {
keyAlias 'xmg'
keyPassword '123456'
storeFile file('/Users/kay/Desktop/release_key.jks')
storePassword '123456'
}
}
定義了兩種型別的簽名配置。
設定好籤名配置,我們要給不同型別的構建設定簽名。
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.realse
}
debug{
applicationIdSuffix ".debug"
versionNameSuffix "huangkai"
}
}
在上面的程式碼,我們給釋出版設定了簽名配置。
為了驗證簽名配置的情況,我們切換到Terminal對話方塊,在對話方塊下輸入以下命令
./gradlew assembleRelease
除了可以使用配置的情況,我們也可以使用ide來配置達到一樣的效果。
7.2.3.2 定製版本 productFlavors
我們現在在中國開發要面對大量的渠道商(360市場、小米商店、應用寶),為了統計不同的渠道商,我們需要提供不同的版本。這樣就會給開發者增加大量的開發任務,而且也出現程式碼管理的問題。原來在eclipse的環境下,我們需要將程式碼複製多份,再執行打包指令碼,打包成不同的渠道包。但是現在使用gradle進行程式碼管理,我們就不需要在做這個了,我們可以使用gradle來定製不同的版本,最後gradle會根據一定的規則把程式碼或者資源進行融合,最後生成我們需要的apk。
在android{}模組內部增加以下的程式碼
productFlavors{
free{
}
pay{
}
}
我們定義了當前的應用有兩個版本,一個是free(免費),pay(收費)。我們預計要打兩個版本的包。這裡組合起來有四個版本。
- freeDebug
- freeRelease
- payDebug
- payRelease
定製版本的資源合併
gradle把不同版本的資料夾下的資源進行合併與替換,假設free與pay版本的區別在與某個資原始檔。
我們在src檔案中建立相關的資原始檔夾。
接著我們在各個資源夾中建立一個string.xml資原始檔,接著編寫以下內容
!!!! 注意,在各個資原始檔夾下的內容要不一樣才看得到區別。
接著我們編寫一個activity放置在main資料夾內,在activity的佈局顯示這個字串title。
在左下方選擇相應的構建型別,比如說我們選擇的是payDebug
編寫程式碼完成後,我們可以使用命令列來構建相應的版本。
./gradlew assembleFreeRelease
總結一下,同名的資原始檔可以存在不同的版本檔案內。
定製版本的java合併
上面的例子我們是通過一個資源來區分應用的版本,在實際的開發中,也存在這樣的情況,不同的版本可能有不一樣的業務邏輯,所以我們可能需要在不同的版本里面處理java程式碼。
首先我們還是在之前的專案結構上面進行開發,這裡有兩個版本,一個free,一個pay。
首先我們先選擇一個build variants,在這裡我們選擇payDebug。
選擇完成後,我們開啟pay資料夾,我們需要建立一個Activity。我們知道java程式碼再android studio下面預設是存放在java資料夾下的。所以我們需要建立一個Java資料夾。
同樣的步驟我們在free資料夾也操作一遍
我們發現了free 和 pay 的Java資料夾顏色不一樣,pay的變成了藍色,free還是普通的黃色。
我們嘗試新建一個class。
很明顯在free檔案上面沒法新建類。為什麼呢?
因為我們之前選擇的payDebug,ide就只編譯了pay資料夾下面的Java類。如果我們選擇了freeDebug,情況就剛好相反。
我們在free 和 pay 下面建立了兩個同名的activity,並指派了不同的介面。分別執行後,發現每次執行只能選其中一種顯示。
接著我們在main資料夾下面建立一個類,Util。接著我們無論在free或者pay下面都無法建立同名的類了,均會提示我們重複建立類錯誤。
總結一下:
- 1 main 資料夾下有A類,那個其他版本的資料夾內不能有同名的類A
- 2 不同版本的相同的檔案A類,執行的時候請選擇相應的build variants
上面的例子是我們使用productFlavors合併了java程式碼。
7.2.3.3 定製版本組合 flavorDimensions
在專案中,我們可能會碰到這樣的需求,我們可能需要對某個版本提供特殊的功能,但是這個功能與當前的定製版本程式碼差別不大,如果根據每個定製版本都再新建一個定製版本出來就優點複雜了。比如說我們根據上面的例子來說,當前的應用提供了兩個定製版本,一個是pay,一個是free。但是專案在測試的時候,測試組希望根據版本提供有log訊息和沒有log訊息的版本。根據之前的我們需要新建payLog,payNoLog,freeLog,freeNoLog等版本。看起來還行吧,但是如果不止兩個而是5個版本,pay,free,….free5,而且log和noLog的區別可能就是幾句程式碼。那個這個專案的結構就太過複雜了。這個時候,我們就可以使用定製版本組合。
定製版本組合怎麼操作呢,我們根據需求將程式碼分成不同的組,不同的組代表不同的功能,組和組可以互相組合,最終形成需要的版本。相對於productFlavors,flavorDimensions是productFlavors的補充選擇,可以讓我們版本定製更靈活。
以上面的例子來說:
我們可以將版本的需求分成兩個維度,一個是支付狀態,一個是輸出訊息狀態。
flavorDimensions "log","pay_status"
首先定義兩個維度。下面我們要指定版本屬於哪個維度。
productFlavors {
withLog{
dimension "log"
}
noLog{
dimension "log"
}
free {
dimension "pay_status"
}
pay {
dimension "pay_status"
}
}
最後gradle會自動組合版本
7.2.3.4 定製版本依賴
我們在上面的內容學習了依賴的寫法,但是之前我們學習依賴的時候,這個依賴的是對這個專案整體生效的。意思就是專案所有的版本都生效,但是在實際開發中,我們可能會碰到這樣的情況,比如說我們開發一個應用,這個應用分成收費版本和免費版本。收費版本不需要顯示廣告。免費版本因為沒有付費,需要顯示廣告。在這裡我們需要對我們的定製版本的依賴做細化的區分。原來在eclipse的時候,我們只能通過複製多一份程式碼來進行實現。現在我們可以同過gradle實現。
free {
dimension "pay_status"
dependencies {
freeCompile 'com.bm.photoview:library:1.4.1'
}
}
在上面的程式碼我們在版本定製內部添加了一個xxxxCompile的標籤,這個意思就是告訴gradle是什麼版本的依賴。xxxx是這個版本的名稱。
7.2.3.5 packagingOptions 打包選項
我們可以使用這個引數來告訴Gradle什麼檔案打包到apk內,什麼檔案不打包,重複檔案如何處理等。
- pickFirst 路徑,如果檔案匹配這個路徑,只有第一個檔案打包進apk
- Merge 合併兩個檔案進入apk,第二個檔案會在第一個檔案後
Exclude 不打包的檔案的路徑
packagingOptions {
//以下檔案不加入apk裡
exclude ‘LICENSE.txt’
}