Android Studio不僅可以為app或者library創(chuàng)建模塊,還可以為Android Wear,Android TV,Google App Engine等創(chuàng)建模塊夭谤。所有的這些模塊可以在一個工程中使用。你可能想要創(chuàng)建一個程序邮利,它使用Google Cloud Endpoints作為后臺馋吗,并與Android Wear集成。這種情況下夜畴,你的工程中需要有三個模塊:app、后臺删壮、Android Wear集成贪绘。了解多模塊工程的結構和構建,可以極大縮短你的開發(fā)周期央碟。
Gradle和Gradle Android插件的文檔都使用了多工程構建(multiproject builds)這一術語税灌。在Android Studio中,
module
和project
是有區(qū)別的亿虽。比如菱涤,一個模塊可以是一個Android app或者一個Google App Engine后臺。而一個工程是一個模塊的集合洛勉。本書為避免混淆粘秆,使用IDE中的概念來理解module
和project
。在瀏覽文檔時要謹記收毫。
本章講解多模塊構建翻擒,并提供一些對實際工程很有用的示例。
- 多模塊構建的剖析
- 為工程添加模塊
- 技巧和最佳實踐
多模塊構建的剖析
通常一個多模塊工程會有一個根目錄牛哺,每一個模塊有一個子目錄。為了讓Gradle知道工程的結構劳吠,以及每個子目錄是什么模塊引润,你需要在根目錄添加一個settings.gradle
文件。每個模塊可以提供它自己的build.gradle
文件痒玩。我們在第二章已經(jīng)介紹了settings.gradle
文件和build.gradle
文件的作用淳附,這里我們介紹如何在多模塊工程中使用它們议慰。
下面是多模塊工程的結構:
project
├─── setting.gradle
├─── build.gradle
├─── app
│ └─── build.gradle
└─── library
└─── build.gradle
這是設置多模塊工程最簡單和直接的方式。settings.gradle
文件聲明了工程的所有模塊:
include ':app', ':library'
這保證了app
和library
模塊包含在構建配置中奴曙。你需要做的只是將模塊所在的目錄添加進來别凹。
你需要將以下代碼添加到app模塊的build.gradle
文件中,以便app
模塊將library
模塊添加為依賴:
dependencies {
compile project(':library')
}
為給模塊添加依賴洽糟,你需要使用project()
方法炉菲,參數(shù)為模塊路徑。
如果你想使用子目錄來組織模塊坤溃,Gradle也可以滿足需求拍霜。比如,你的目錄結構可能是這個樣子的:
project
├─── setting.gradle
├─── build.gradle
├─── app
│ └─── build.gradle
└─── libraries
├─── library1
│ └─── build.gradle
└─── library2
└─── build.gradle
app模塊還在根目錄下薪介,但工程有兩個庫祠饺。這些庫不在工程的根目錄下。你可以在settings.gradle
文件中如下聲明各個模塊:
include ':app', ':libraries:library1', ':libraries:library2'
可以看到聲明子目錄中的模塊也是很容易的汁政。路徑是相對于根目錄(settings.gradle
文件所在的目錄)的道偷。冒號用于替換路徑中的斜杠。
在將一個子目錄模塊添加為另一個模塊的依賴時记劈,你應該從根目錄引用它勺鸦。也就是說,如果上例中的app模塊依賴于library
的話抠蚣,app模塊的builde.gradle
文件應該這樣寫:
dependencies {
compile project(':libraries:library1')
}
Gradle在構建工程依賴時祝旷,總是相對于根目錄。
重溫構建的生命周期
了解構建過程模型是如何構造的嘶窄,可以更容易地理解多模塊項目是如何組成的怀跛。我們已經(jīng)在第一章提到過構建的生命周期,所以你已經(jīng)有了基礎柄冲,但是一些細節(jié)對于多模塊構建來說也是很重要的吻谋。
在第一階段,即initialization
期間现横,Gradle首先找到settings.gradle
文件漓拾。如果這個文件不存在,Gradle認為這是一個單模塊的構建戒祠。如果你有多個模塊骇两,你需要在settings
文件中定義包含每個模塊的子目錄。如果這些子目錄有它們自己的build.gradle
文件姜盈,Gradle將會自動處理低千,并將它們合并到構建過程模型中。這解釋了為什么你需要在模塊中用相對路徑聲明依賴馏颂。Gradle會嘗試從根目錄中找出依賴項示血。
一旦你了解了構建過程模型是如何組合在一起的棋傍,配置多模塊構建的幾種策略將變得非常清晰。
- 你可以在根目錄的
build.gradle
文件中配置所有模塊难审。這會使瀏覽工程的整個構建配置變得很容易瘫拣,但是結構會混亂,尤其是在各個模塊需要不同的插件告喊,每個插件擁有自己的DSL時麸拄。 - 另一種方式是為每個模塊單獨配置
build.gradle
文件。這可以解耦各個模塊葱绒。它還使跟蹤構建更改變得容易感帅,因為你不需要知道哪個模塊應用了哪個更改。 - 最后一個策略是混合使用地淀。你可以在根目錄的構建文件中定義所有模塊通用的屬性失球,在每個模塊的構建文件中定義各自模塊的配置。Android Studio使用了這個方式帮毁。它會在根目錄創(chuàng)建一個
build.gradle
文件实苞,并為各個模塊創(chuàng)建自己的build.gradle
文件。
模塊任務
一旦你的工程中有了多個模塊烈疚,你就需要在運行任務前多思考一下黔牵。當你在工程根目錄下通過命令行窗口運行任務時,Gradle會找出所有模塊中的同名任務爷肝,并運行它們猾浦。比如,你有一個app模塊和一個Android Wear模塊灯抛,運行gradlew assembleDebug
將會為app模塊和Android Wear模塊都構建一個debug版本金赦。如果你切換到模塊的目錄下,Gradle將只會運行該模塊的任務对嚼,即使你在工程根目錄中運行Gradle Wrapper夹抗。比如,在Android Wear模塊的目錄運行../gradlew assembleDebug
纵竖,只會構建Android Wear模塊漠烧。
切換目錄的方式來運行模塊的任務是比較繁瑣的。另一個方式是可以使用模塊名稱來預處理任務名稱靡砌,使運行任務只在那個模塊上運行已脓。比如只想構建Android Wear模塊,可以使用gradlew :wear:assembleDebug
命令通殃。
為工程添加模塊
Android Studio有向?qū)б龑愫唵我锥奶砑右粋€模塊摆舟。向?qū)б矔闃嫿ㄎ募砑右恍┗緝?nèi)容。某些情況下,添加一個模塊會使Android Studio編輯app模塊的構建文件恨诱。比如,在添加一個Android Wear模塊的時候骗炉,IDE會認為你想在Android app中使用它照宝,因此會在構建文件中添加對Android Wear模塊的引用。
在接下來的部分句葵,我們將會展示Android Studio中的工程可以添加的幾個不同的模塊厕鹃,介紹它們的屬性,以及它們?nèi)绾斡绊憳嫿ㄟ^程乍丈。
添加一個Java庫
在你添加一個新的Java庫模塊的時候剂碴,build.gradle
文件如下:
apply plugin: 'java'
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
Java庫模塊使用了Java插件而不是我們經(jīng)常看到的Android插件轻专。這表示很多Android特有的屬性和任務是無法使用的忆矛,而對于Java庫來說也并不需要它們。
構建文件還建立了基本依賴管理请垛,所以你可以在libs
文件夾添加JAR包催训,而不需要任何特殊配置。你可以用第三章學到的知識添加更多的依賴宗收。依賴配置不依賴于Android插件漫拭。
比如,為了給app模塊添加一個名為javalib
的Java庫模塊你只需要在app模塊的構建文件中添加一行代碼:
dependencies {
compile project(':javalib')
}
這樣Gradle就會在構建時導入一個名為javalib
的模塊混稽。如果你在app模塊添加了這個依賴采驻,那么在app模塊開始構建之前,javalib
模塊會先被構建匈勋。
添加一個Android庫
我們在第三章簡單提及了Android庫礼旅,并稱之為庫工程。在文檔和各種教程中颓影,都用到了這兩個名稱各淀。在這一部分內(nèi)容中,我們使用Androidlibrary
(Android庫)這個名稱诡挂,因為這是在Android Studio的New Module對話框中使用的名稱碎浇。
Android庫的build.gradle
文件起始代碼如下:
apply plugin: 'com.android.library'
添加Android庫為依賴和添加Java庫是一樣的:
dependencies {
compile project(':androidlib')
}
一個Android庫不僅包含Java代碼,還包括所有的Android資源璃俗,比如manifest文件奴璃、字符串和布局等。添加Android庫為依賴后城豁,你可以使用庫中所有的類和資源苟穆。
集成Android Wear
如果你想在Android Wear中加入深度集成的應用程序,你需要添加Android Wear模塊。Android Wear模塊同樣使用了Android application插件雳旅,所以所有的構建屬性和任務都可以使用跟磨。
build.gradle
文件唯一和常規(guī)Android app模塊不同的部分是依賴配置:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.google.android.support:wearable:1.1.0'
compile 'com.google.android.gms:play-services-wearable:6.5.87'
}
每個Android Wear應用都依賴一些Google提供的Wear特有的庫。為了在Android app中使用Android Wear app攒盈,你需要將它打包進app中抵拘。你可以在Android app中添加一個依賴:
dependencies {
wearApp project(':wear')
}
wearApp
配置確保Wear APK打包進最終的Android app的APK中,并為你做了必要的配置型豁。
使用Google App Engine
Google App Engine是一個云計算平臺僵蛛,您可以使用它來托管web應用程序,而無需設置自己的服務器迎变。在一定程度上它是免費的充尉,這使它成為一個很好的實驗環(huán)境。Google App Engine還提供一個稱謂Cloud Endpoints(云終端)的服務衣形,它可以用來創(chuàng)建基于REST的服務驼侠。使用Google App Engine和Cloud Endpoints可以很容易地為你的應用構建一個后臺。Gradle App Engine插件通過為你的app生成一個客戶端庫使其變得更加簡單泵喘,這意味著你不需要自己去寫任何API相關的代碼泪电。這就使Google App Engine成為app后臺的一個選擇,所以結下來的部分我們會學習App Engine如何工作纪铺,以及如何使用Cloud Endpoints相速。
為了創(chuàng)建一個新的包含Cloud Endpoints的Google App Engine模塊,你需要從File|New Module...菜單打開New Module對話框鲜锚,然后選擇Google Cloud Module突诬。在模塊設置中,你可以修改種類來包含Cloud Endpoints芜繁。然后旺隙,選擇使用這個后臺的客戶端模塊。
對Google App Engine和Cloud Endpoints進行透徹的講解超出了本書的范疇骏令,我們只會講解Gradle對App Engine模塊和客戶端app模塊的集成蔬捷。
分析構建文件
這個模塊的構建文件非常大,所以我們只關注幾個部分榔袋,首先是構建腳本依賴:
buildscript {
dependencies {
classpath 'com.google.appengine:gradle-appengine-plugin:1.9.18'
}
}
App Engine插件需要定義在構建腳本的類路徑中周拐。我們在之前添加Android插件時已經(jīng)見到過。設置好之后凰兑,我們可以應用App Engine插件和另外兩個插件:
apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'appengine'
Java插件主要用來為Cloud Endpoints生成Jar文件妥粟。WAR插件用來運行和分發(fā)整個后臺。WAR插件生成一個WAR文件吏够,Java web應用在此分布勾给。最后滩报,App Engine插件添加一系列任務來構建、運行和配置整個后臺播急。
下一個重要的塊定義了App Engine模塊的依賴:
dependencies {
appengineSdk 'com.google.appengine:appengine-java-sdk:1.9.18'
compile 'com.google.appengine:appengine-endpoints:1.9.18'
compile 'com.google.appengine:appengine-endpoints-deps:1.9.18'
compile 'javax.servlet:servlet-api:2.5'
}
第一個依賴使用appengineSdk
指明模塊需要用到的SDK脓钾。Cloue Endpoints需要endpoints
依賴才能運行。這些只在你使用Cloud Endpoints時才會添加桩警。servlet
依賴是每個Google App Engine模塊所必需的惭笑。
在appengine
塊中設置App Engine特有的配置:
appengine {
downloadSdk = true
appcfg {
oauth2 = true
}
endpoints {
getClientLibsOnBuild = true
getDiscoveryDocsOnBuild = true
}
}
將downloadSdk
屬性設置為true
,可以很容易地運行本地開發(fā)服務器生真,因為如果SDK不存在的話,它會自動下載SDK捺宗。如果你已經(jīng)在自己的設備上配置好了Google App Engine SDK柱蟀,你可以將downloadSdk
設置為false
。
appcfg
塊用來配置App Engine SDK蚜厉。在一個典型的Google App Engine安裝中长已,你可以在命令行中使用appcfg
來手動設置一些配置。使用appcfg
塊來代替命令行工具昼牛,使設置更加便捷术瓮,每個構建該模塊的人都有同樣的配置,從而不必去執(zhí)行一些額外的命令贰健。
endpoints
塊包含一些Cloud Endpoints特有的設置胞四。
關于Google App Engine和Cloud Endpoints更詳細的說明超出了本書的范疇。如果你想學習更多伶椿,可以訪問https://cloud.google.com/appengine/docs
在app中使用后臺
當你創(chuàng)建一個App Engine模塊時辜伟,Android Studio會自動在Android app模塊的構建文件中添加一個依賴。如下:
dependencies {
compile project(path: ':backend', configuration: 'android-endpoints')
}
我們已經(jīng)見過這種語法(在引用Java和Android庫時)脊另,使用project
來定義依賴导狡,并帶有兩個參數(shù)。path
參數(shù)是默認參數(shù)偎痛,我們之前就用過旱捧,但是沒有指明它的名稱。一個Google App Engine模塊可以有不同種類的輸出踩麦。你可以使用configuration
參數(shù)來指明你想要的輸出枚赡。我們需要App Engine模塊生成Cloud Endpoints,所以設置為android-endpoints
。在內(nèi)部靖榕,這個配置會運行_appengineEndpointsAndroidArtifact
任務标锄。這個任務生成一個JAR文件,包含你可以在Android app模塊中使用的類茁计。這個JAR文件不僅包含Could Endpoints中使用的模型料皇,還有API方法谓松。像這樣的集成使得多模塊項目很好地工作,因為它縮短了開發(fā)時間践剂。App Engine模塊中的Gradle任務也使運行和部署后臺變得更加容易鬼譬。
自定義任務
App Engine插件添加了很多任務,用的最多的是appengineRun
和appengineUpdate
逊脯。
appengineRun
任務用來啟動一個本地開發(fā)服務器优质,在上傳到Google App Engine之前,你可以用它來對整個后臺進行本地測試军洼。第一次啟動這個任務可能會多消耗一點時間巩螃,因為Gradle需要下載App Engine SDK(我們之前設置了downloadSdk = true
)。你可以使用appengineStop
來停止服務器運行匕争。
一旦你要將后臺部署到Google App Engine并在生產(chǎn)環(huán)境使用它避乏,你可以使用appengineUpdate
。這個任務處理部署的所有細節(jié)甘桑。如果你設置了oauth2 = true
拍皮,這個任務會打開一個瀏覽器窗口,你可以登錄你的Google賬戶并拿到一個身份令牌跑杭。如果你不想每次部署時都需要登錄铆帽,你可以用Google賬戶登錄Android Studio并使用IDE部署后臺。Android Studio會運行同樣的任務德谅,但是它會接管認證爹橱。
技巧和最佳實踐
有一些技巧使處理多模塊工程變得簡單,在處理一些模塊時女阀,你需要牢記一些事情宅荤。了解這些可以使你省時又省心。
從Android Studio中運行模塊任務
正如在第二章看到的浸策,Android Studio可以直接運行Gradle任務冯键。當你有多個模塊時,Android Studio可以識別它們庸汗,并可以分模塊預覽可用的任務惫确。
Gradle工具窗口可以很容易的運行模塊特有的任務。窗口中并沒有為所有模塊同時運行任務的選項蚯舱,所以如果你想這么做改化,還是需要使用命令行。
加快多模塊的構建
在你構建一個多模塊工程時枉昏,Gradle會串行處理所有的模塊陈肛。在電腦有多核可用時,我們可以利用并行處理加速構建過程兄裂。Gradle已經(jīng)有這個特性句旱,但是默認沒有開啟阳藻。
如果你想開啟并行處理,需要在工程根目錄的gradle.properties
文件中設置parallel
屬性:
org.gradle.parallel=true
Gradle會基于CPU的核心數(shù)量選擇適當?shù)木€程數(shù)谈撒。為了避免同時執(zhí)行一個模塊的兩個任務可能產(chǎn)生的問題腥泥,一個模塊會在一個線程中執(zhí)行。
并行構建執(zhí)行是一個孵化特性啃匿。這意味著它在積極的發(fā)展蛔外,某個時候可能會改變。這個特性目前是Gradle的一部分溯乒,并被廣泛使用夹厌。所以,它應該不會突然消失或者改變裆悄。
開啟并行構建可能會省掉你的大筆時間尊流。為了更有效率的執(zhí)行,需要確保模塊沒有耦合灯帮。
模塊耦合
如第二章所見,可以在頂級構建文件中逻住,使用allprojects
為所有的模塊定義屬性钟哥。在多模塊工程中,你可以在任何模塊中使用allprojects
為工程中的所有模塊應用屬性瞎访。Gradle甚至使你可以在一個模塊中引用另一個模塊的屬性腻贰。這個強大的特性可以使維護多模塊構建變得簡單,弊端就是會造成模塊耦合扒秸。
一旦兩個模塊需要訪問彼此的任務或者屬性播演,則被認為是耦合的。這會造成幾個后果伴奥。比如写烤,你放棄了可移植性。如果你決定從項目中提取一個庫拾徙,那么在復制所有項目范圍的設置之前洲炊,你將無法構建。模塊耦合也會影響并行構建尼啡。在任何模塊使用allprojects
塊將使并行構建無效暂衡。當你在任何模塊添加項目范圍的屬性時要牢記這些。
你可以通過不直接訪問其他模塊的任務或者屬性來避免耦合崖瞭。如果你需要這么做狂巢,你可以使用根模塊作為中介,這樣模塊就會變成和根模塊耦合书聚,而不是相互耦合唧领。