Gradle for Android(五) 管理多模塊構建

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中,moduleproject是有區(qū)別的亿虽。比如菱涤,一個模塊可以是一個Android app或者一個Google App Engine后臺。而一個工程是一個模塊的集合洛勉。本書為避免混淆粘秆,使用IDE中的概念來理解moduleproject。在瀏覽文檔時要謹記收毫。

本章講解多模塊構建翻擒,并提供一些對實際工程很有用的示例。

  • 多模塊構建的剖析
  • 為工程添加模塊
  • 技巧和最佳實踐

多模塊構建的剖析

通常一個多模塊工程會有一個根目錄牛哺,每一個模塊有一個子目錄。為了讓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'

這保證了applibrary模塊包含在構建配置中奴曙。你需要做的只是將模塊所在的目錄添加進來别凹。

你需要將以下代碼添加到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芜繁。然后旺隙,選擇使用這個后臺的客戶端模塊。

圖1 Android Studio創(chuàng)建App Engine模塊對話框

對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插件添加了很多任務,用的最多的是appengineRunappengineUpdate逊脯。

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可以識別它們庸汗,并可以分模塊預覽可用的任務惫确。

圖2 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塊將使并行構建無效暂衡。當你在任何模塊添加項目范圍的屬性時要牢記這些。

你可以通過不直接訪問其他模塊的任務或者屬性來避免耦合崖瞭。如果你需要這么做狂巢,你可以使用根模塊作為中介,這樣模塊就會變成和根模塊耦合书聚,而不是相互耦合唧领。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末藻雌,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子疹吃,更是在濱河造成了極大的恐慌蹦疑,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件萨驶,死亡現(xiàn)場離奇詭異歉摧,居然都是意外死亡,警方通過查閱死者的電腦和手機腔呜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門叁温,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人核畴,你說我怎么就攤上這事膝但。” “怎么了谤草?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵跟束,是天一觀的道長。 經(jīng)常有香客問我丑孩,道長冀宴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任温学,我火速辦了婚禮略贮,結果婚禮上,老公的妹妹穿的比我還像新娘仗岖。我一直安慰自己逃延,他們只是感情好,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布轧拄。 她就那樣靜靜地躺著揽祥,像睡著了一般。 火紅的嫁衣襯著肌膚如雪檩电。 梳的紋絲不亂的頭發(fā)上盔然,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機與錄音是嗜,去河邊找鬼愈案。 笑死,一個胖子當著我的面吹牛鹅搪,可吹牛的內(nèi)容都是我干的站绪。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼丽柿,長吁一口氣:“原來是場噩夢啊……” “哼恢准!你這毒婦竟也來了魂挂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤馁筐,失蹤者是張志新(化名)和其女友劉穎涂召,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體敏沉,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡果正,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了盟迟。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片秋泳。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖攒菠,靈堂內(nèi)的尸體忽然破棺而出迫皱,到底是詐尸還是另有隱情,我是刑警寧澤辖众,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布卓起,位于F島的核電站,受9級特大地震影響凹炸,放射性物質(zhì)發(fā)生泄漏既绩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一还惠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧私杜,春花似錦蚕键、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至铝耻,卻和暖如春誊爹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瓢捉。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工频丘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人泡态。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓搂漠,卻偏偏與公主長得像,于是被迫代替她去往敵國和親某弦。 傳聞我的和親對象是個殘疾皇子桐汤,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容