持續(xù)集成【Continuous integration (CI)】是一種開發(fā)實(shí)踐则剃,它要求團(tuán)隊(duì)的開發(fā)人員定期集成他們的工作挑胸,經(jīng)常每天進(jìn)行幾次碎捺。向主倉庫的每個(gè)push由自動化構(gòu)建進(jìn)行驗(yàn)證箱歧。這種實(shí)踐有助于快速發(fā)現(xiàn)問題炎功,從而加快開發(fā)速度凤薛,提升代碼質(zhì)量姓建。偉大的Martin Fowler寫了一片文章來講解這個(gè)概念诞仓,描述最佳實(shí)踐http://martinfowler.com/articles/continuousIntegration.html。
為Android設(shè)置CI有幾種選擇速兔。用的最廣泛的有Jenkins,TeamCity,Travis CI墅拭。Jenkins擁有最大的生態(tài)系統(tǒng),大約有1000個(gè)插件涣狗。它是開源的谍婉,有大量的貢獻(xiàn)者。TeamCity是JetBrains的一個(gè)產(chǎn)品屑柔,該公司同樣創(chuàng)造了IntelliJ IDEA屡萤。Travis CI相對比較新,主要用于開源項(xiàng)目掸宛。
我們將研究這些CI系統(tǒng)死陆,以及如何同Gradle協(xié)同工作。在本章末尾唧瘾,我們會提及一些Gradle技巧措译,使CI更加容易。
本章內(nèi)容有:
- Jenkins
- TeamCity
- Travis CI
- 進(jìn)一步自動化
Jenkins
Hudson最初由Sun公司于2005年發(fā)布饰序,那是Jenkins的原型领虹。這些年,它逐漸成為了Java社區(qū)最流行的CI系統(tǒng)求豫。Sun被Oracle收購不久塌衰,Oracle和Java社區(qū)關(guān)于Hudson有了沖突。在無法解決的情況下蝠嘉,社區(qū)繼續(xù)以Jenkins為名稱運(yùn)行該項(xiàng)目最疆,因?yàn)镠udson被Oracle所有。
Jenkins的強(qiáng)大在于它的插件系統(tǒng)蚤告。任何人對構(gòu)建系統(tǒng)有新功能的需求努酸,都可以創(chuàng)建插件來擴(kuò)展Jenkins的能力。這也是為什么為Android應(yīng)用或者庫配置一個(gè)自動化構(gòu)建如此簡單的原因杜恰。
配置Jenkins
如果你的電腦還沒有安裝获诈,可以在https://jenkins-ci.org下載。
在使用Jenkins之前心褐,你需要確保已安裝了所有構(gòu)建Android app和library所需的庫舔涎。構(gòu)建任何Java相關(guān)的東西,你需要安裝JDK逗爹。
你同樣需要確保安裝了Android SDK和build tools亡嫌。你不必在構(gòu)建服務(wù)器上安裝IDE,除非你打算打開項(xiàng)目。
在Java和Android SDK安裝后昼伴,你需要在Jenkins中配置它們。首先需要用瀏覽器打開Jenkin的首頁镣屹,點(diǎn)擊Manage Jenkins|Configure System圃郊,滾動到Global properties。添加ANDROID_HOME,JAVA_HOME這兩個(gè)環(huán)境變量女蜈,分別指向android SDK目錄和java目錄持舆。
你還需要安裝Gradle插件。點(diǎn)擊Manage Jenkins|Manage Plugins伪窖,打開Available標(biāo)簽逸寓,搜索Gradle。定位到Gradle插件后覆山,選擇選框竹伸,點(diǎn)擊Download now and install after restart。該插件可以創(chuàng)建Gradle相關(guān)的構(gòu)建步驟簇宽。
構(gòu)建配置
安裝了所有需要的東西后勋篓,你就可以在Jenkins中創(chuàng)建一個(gè)CI工程了。首先你需要設(shè)置VCS倉庫魏割,這樣Jenkins才知道去哪里找項(xiàng)目的源碼譬嚣。你可以基于庫的事件來設(shè)置Jenkins自動構(gòu)建Android app或者library,也可以使用觸發(fā)器或者手動構(gòu)建钞它。為了開始真正的構(gòu)建拜银,你需要調(diào)用Gradle腳本來添加一個(gè)新的構(gòu)建步驟。你可以配置Jenkins使用Gradle Wrapper遭垛。使用Gradle Wrapper不僅可以避免手動安裝Gradle尼桶,還可以確保Gradle自動更新。選擇Make gradlw executable也是非常好的耻卡。這解決了Windows系統(tǒng)創(chuàng)建的項(xiàng)目疯汁,執(zhí)行Gradle Wrapper的權(quán)限問題。
你可以為構(gòu)建步驟輸入一個(gè)描述卵酪,并可以選擇打開兩個(gè)開關(guān):info,stacktrace幌蚊。info用來打印構(gòu)建過程的信息,這在排查錯(cuò)誤時(shí)非常有用溃卡。如果構(gòu)建出現(xiàn)了異常溢豆,stacktrace開關(guān)會打印出異常的堆棧信息。有時(shí)你可能需要更加詳細(xì)的信息瘸羡,這時(shí)你可以打開full-stacktrace開關(guān)漩仙。
為了完成配置,你需要指定想要執(zhí)行的Gradle任務(wù)。首先队他,執(zhí)行clean
任務(wù)卷仑,確保沒有上一個(gè)構(gòu)建的殘留輸出。其次麸折,執(zhí)行build
任務(wù)锡凝,這會觸發(fā)所有構(gòu)建變體進(jìn)行構(gòu)建。Jenkins配置如下:
保存項(xiàng)目配置后垢啼,就可以構(gòu)建了窜锯。
如果你的構(gòu)建服務(wù)器安裝在64位的Linux系統(tǒng)上,可能出現(xiàn)異常
java.io.IOException:Cannot run program "aapt": error=2, No such file or directory
芭析。這是因?yàn)锳APT是32位的程序锚扎,在64位系統(tǒng)上運(yùn)行需要額外庫的支持∧倨簦可以通過如下命令安裝所需的庫:$ sudo apt-get install lib32stdc++6 lib32z1
如果構(gòu)建沒有問題驾孔,它會為所有的構(gòu)建變體創(chuàng)建一個(gè)APK。你可以指定Gradle任務(wù)來分發(fā)這些APK进统。在本章末尾我們會提及自動分發(fā)助币,因?yàn)檫@是每個(gè)構(gòu)建系統(tǒng)都有的。
TeamCity
與Jenkins不同螟碎,TeamCity是一個(gè)專賣產(chǎn)品眉菱,只對開源項(xiàng)目免費(fèi)。它由JetBrains公司制作和管理掉分。TeamCity內(nèi)置支持Gradle Android構(gòu)建俭缓。
設(shè)置TeamCity
如果你還沒有安裝TeamCity,可以去JetBrains官網(wǎng)下載(https://www.jetbrains.com/teamcity)酥郭。
為使TeamCity可以構(gòu)建Android app或者library华坦,你需要確保安裝了JDK,Android SDK以及Android build tools不从。你同樣需要將ANDROID_HOME添加到電腦的環(huán)境變量中惜姐。
與Jenkins不同的是,TeamCity不需要任何插件來觸發(fā)Gradle構(gòu)建椿息,TeamCity內(nèi)置支持運(yùn)行Gradle歹袁。
構(gòu)建配置
你需要創(chuàng)建一個(gè)新的項(xiàng)目來配置Android構(gòu)建。你僅需要提供一個(gè)名稱寝优。創(chuàng)建了項(xiàng)目条舔,就可以進(jìn)行配置了。首先乏矾,你需要添加一個(gè)VCS根目錄孟抗,這樣TeamCity就可以找到項(xiàng)目的源碼了迁杨。然后你需要創(chuàng)建一個(gè)新的構(gòu)建配置。你同樣需要將VCS跟目錄綁定到構(gòu)建配置中凄硼。設(shè)置好這些铅协,你就可以添加一個(gè)新的構(gòu)建步驟。如果你點(diǎn)擊了Auto-detect build steps按鈕摊沉,TeamCity會嘗試選擇必需的構(gòu)建步驟警医,這基于項(xiàng)目的內(nèi)容。在基于Gradle的Android項(xiàng)目中坯钦,配置結(jié)果去下:
TeamCity檢測到項(xiàng)目使用了Gradle,并且Gradle Wrapper可用侈玄。你僅需要選擇Gradle構(gòu)建步驟婉刀,并將其添加到構(gòu)建配置中。如果你不需要做其他任何過多的事情序仙,這些足夠確保構(gòu)建你的Android app突颊。你可以測試配置,只需要打開項(xiàng)目預(yù)覽潘悼,點(diǎn)擊Run...按鈕律秃。
Travis CI
如果你的項(xiàng)目倉庫托管在GitHub上,你可以使用Travis CI進(jìn)行自動構(gòu)建治唤。Travis CI(https://travis-ci.org)是一個(gè)開源的托管持續(xù)集成系統(tǒng)棒动,對開源倉庫免費(fèi)。它對私有倉庫是收費(fèi)的宾添,本書只討論免費(fèi)的情況船惨。
Travis會檢測新的提交,并自動開始一個(gè)新的構(gòu)建缕陕。Travis默認(rèn)構(gòu)建所有分支粱锐,不僅僅是主分支。它同樣會自動構(gòu)建pull request扛邑。
由于Travis在內(nèi)部工作怜浅,你無法配置構(gòu)建服務(wù)器本身。你需要創(chuàng)建一個(gè)新的配置文件蔬崩,包含所有的Travis構(gòu)建你的app或者library的信息恶座。
構(gòu)建配置
如果你想使用Travis構(gòu)建你的項(xiàng)目,你首先需要登錄Travis CI舱殿,并連接到你的Github賬戶奥裸。做好了這些,你需要在設(shè)置中選擇你想構(gòu)建的項(xiàng)目沪袭。
為了配置構(gòu)建過程湾宙,Travis要求你創(chuàng)建一個(gè)名為.travis.yml
的文件樟氢,包含整個(gè)配置。為了配置Android項(xiàng)目侠鳄,你需要添加一些Android特有的屬性:
language: android
android:
components:
# The build tools version used by your project
- build-tools-22.0.1
# The SDK version used to compile your project
- android-22
# Additional components
- extra-android-m2repository
語言設(shè)置指定你想要運(yùn)行的構(gòu)建過程埠啃。上述情況下,你在構(gòu)建一個(gè)Android app伟恶。Android特定屬性包含構(gòu)建工具版本和Android SDK版本碴开。Travis會在執(zhí)行build
任務(wù)之前下載這些東西。如果你使用了support library或者Google Play Services博秫,你需要明確指定潦牛,因?yàn)門ravis也需要去下載這些依賴。
Travis并不強(qiáng)制要求配置build tools和SDK版本挡育,但是確保它們的版本和你在
build.gradle
文件定義的版本一致巴碗,會使你遇到更少的問題。
如果你在windows系統(tǒng)創(chuàng)建一個(gè)Android項(xiàng)目即寒,Gradle Wrapper可能會有一些權(quán)限問題橡淆。所以,最好在運(yùn)行真正的構(gòu)建腳本之前解決它母赵。你可以添加一個(gè)預(yù)構(gòu)建步驟:
before_script:
# Change Gradle wrapper permissions
- chmod +x gradlew
為了開始構(gòu)建逸爵,需要將一下代碼添加到Travis的配置文件中:
# Let's build
script: ./gradlew clean build
這段代碼會運(yùn)行Gradlw wrapper,執(zhí)行clean
和build
任務(wù)凹嘲。
當(dāng)你完成了Travis構(gòu)建配置后师倔,你可以向項(xiàng)目的Github倉庫提交和推送文件。如果配置都正確周蹭,Travis會啟動構(gòu)建過程溯革,你可以在Travis網(wǎng)站上看到。一個(gè)成功的構(gòu)建如下所示:
Travis在構(gòu)建后還會發(fā)送一封郵件報(bào)告谷醉。如果你是一個(gè)經(jīng)常收到pull request的開源庫的維護(hù)人員致稀,這會非常有用。
你會很快注意到Travis有一個(gè)缺點(diǎn)俱尼,那就是速度抖单。Travis并沒有給你一臺特定機(jī)器,而是為你觸發(fā)的每個(gè)構(gòu)建啟動一個(gè)Vanilla virtual machine(VVM)遇八。也就是說矛绘,對于每個(gè)新的構(gòu)建,Travis在構(gòu)建app或者library之前刃永,需要下載安裝Android SDK和構(gòu)建工具货矮。
從好的方面看,Travis是免費(fèi)和開源的斯够,這使它對于開源項(xiàng)目非常完美囚玫。Travis會自動構(gòu)建pull request喧锦,使你及時(shí)知曉有人為你的代碼提交了補(bǔ)丁。
進(jìn)一步自動化
大多數(shù)時(shí)下的持續(xù)集成系統(tǒng)支持Gradle抓督,或是內(nèi)置支持燃少,或是通過插件支持。這意味著除了僅僅構(gòu)建你的app或者library铃在,你還可以創(chuàng)建所有的Gradle任務(wù)阵具,來進(jìn)一步自動化你的構(gòu)建。使用Gradle任務(wù)定義額外的構(gòu)建步驟定铜,而不是通過CI系統(tǒng)阳液,其優(yōu)勢在于額外的構(gòu)建步驟會變得更加便捷。在你的開發(fā)機(jī)器上運(yùn)行自定義的Gradle任務(wù)非常簡單揣炕。從另一方面看趁舀,一個(gè)自定義的Jenkins構(gòu)建步驟,可以在Jenkins沒有安裝的情況下運(yùn)行祝沸。在一個(gè)特定的CI系統(tǒng)有額外的構(gòu)建步驟使得向其他CI構(gòu)建系統(tǒng)進(jìn)行移植變得非常困難。Gradle任務(wù)也可以非常簡單的移植到不同的項(xiàng)目中越庇。在本節(jié)罩锐,我們會討論幾種方式來使用Gradle任務(wù)和插件,進(jìn)一步實(shí)現(xiàn)自動化構(gòu)建和部署app和library卤唉。
SDK管理器插件
你可能會在某個(gè)時(shí)候遇到一個(gè)問題:構(gòu)建服務(wù)器上的Android SDK不是最新的涩惑。當(dāng)你的app或者library升級SDK版本時(shí),你同樣需要在構(gòu)建服務(wù)器上安裝新的SDK氧敢。如果你有多個(gè)構(gòu)建代理蕊温,這會非常麻煩卜朗。
感謝社區(qū)的努力,有一個(gè)Gradle插件會檢查構(gòu)建所依賴的Android SDK版本是否可用痊硕,如果不可用,插件會自動下載押框。
SDK管理器插件不僅會下載構(gòu)建配置文件指定的編譯SDK岔绸,也會下載正確的build tools和platform tools版本。如果你的項(xiàng)目依賴于support library或者Google Play Services橡伞,該插件也會下載它們盒揉。
SDK管理器插件是一個(gè)開源插件,你可以在GitHub找到源碼(https://github.com/JakeWharton/sdk-manager-plugin)兑徘。
運(yùn)行測試
如果你想在構(gòu)建期間運(yùn)行單元測試(JUnit或者Robolectric)刚盈,你只需要向Gradle的執(zhí)行階段添加相應(yīng)的任務(wù)。如果你想運(yùn)行任何的功能測試挂脑,你需要模擬器來安裝app藕漱,所以你可以使用gradlew connectedAndroidTest
來運(yùn)行測試.
如果你使用Jenkins欲侮,有一個(gè)名為Android Emulator Plugin(https://wiki.jenkins-ci.org/display/JENKINS/Android+Emulator+Plugin)的插件,可以用來為每個(gè)構(gòu)建啟動一個(gè)模擬器谴分。TeamCity同樣有一個(gè)活躍的插件生態(tài)系統(tǒng)锈麸,有一個(gè)名為Android Emulator的插件可以向Jenkins插件一樣用來設(shè)置模擬器。你可以在TeamCity插件官網(wǎng)(https://confluence.jetbrains.com/display/TW/TeamCity+Plugins)找到它牺蹄。
Travis CI也可以啟動一個(gè)模擬器忘伞,但這是一個(gè)實(shí)驗(yàn)功能。如果你使用它沙兰,將下面的代碼片段添加到你的.travis.yml
配置文件中:
# Emulator Management: Create, Start and Wait
before_script:
- echo no | android create avd --force -n test -t android-22 --abi armeabi-v7a
- emulator -avd test -no-skin -no-audio -no-window &
- android-wait-for-emulator
- adb shell input keyevent 82 &
android-wait-for-emulator
指令告知Travis等待模擬器的啟動氓奈。模擬器啟動后,adb shell input keyevent 82 &
會執(zhí)行鼎天,從而解鎖屏幕舀奶。之后,就可以運(yùn)行測試了斋射。
持續(xù)部署
為了幫助開發(fā)者自動部署Android app育勺,Google發(fā)布了Google Play Developer API,一個(gè)以編程方式將APK發(fā)布到Google Play的API(https://developers.google.com/android-publisher)罗岖。這個(gè)API使你不必再打開瀏覽器涧至,登錄Google Play,然后使用web接口上傳APK桑包。你不必再基于Google Play Developer API創(chuàng)建自己的發(fā)布腳本南蓬,而只需要在成功構(gòu)建之后,在構(gòu)建系統(tǒng)中使用眾多插件中的一個(gè)來向Google Play推送APK哑了。
Jenkins有一個(gè)名為Google Play Android Publisher(https://wiki.jenkins-ci.org/display/JENKINS/Google+Play+Android+Publisher+Plugin)的插件可以為你做這些赘方。然而,一個(gè)更好的選擇是使用Gradle插件弱左,這樣你就可以在任何設(shè)備窄陡,任何類型的持續(xù)集成系統(tǒng)中運(yùn)行發(fā)布任務(wù)了。Android社區(qū)的某些人創(chuàng)建了基于Google Play Developer API的Gradle任務(wù)來幫助配置整個(gè)發(fā)布過程拆火。你可以在GitHub(https://github.com/Triple-T/gradle-play-publisher)找到Gradle插件Gradle Play Publisher的源碼泳梆。它也發(fā)布在了Maven Center和JCenter上。
為了使用該插件榜掌,需要在頂級構(gòu)建文件中添加如下語句:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.github.triplet.gradle:play-publisher:1.0.4'
}
}
然后在你的Android模塊的配置文件中應(yīng)用這個(gè)插件:
apply plugin: 'play'
應(yīng)用了Gradle Play Publisher插件后优妙,你會有幾個(gè)新的可用任務(wù):
- publishApkRelease上傳APK和最近的變更
- publishListingRelease上傳描述和圖片
- publishRelease上傳所有東西
如果你有不同的構(gòu)建變體,你也可以運(yùn)行特定變體的版本憎账,比如publishApkFreeRelease
和publishApkPaidRelease
套硼。
為了訪問Google Play Developer API,你需要設(shè)置一個(gè)服務(wù)賬戶胞皱。這個(gè)設(shè)置超出了本書的范圍邪意,但如果你想使用Gradle Play Publisher九妈,這是必需的。你可以在https://developers.google.com/android-publisher/getting_started得到幫助雾鬼。
在你創(chuàng)建了服務(wù)賬戶后萌朱,你可以在構(gòu)建配置文件中添加證書:
play {
serviceAccountEmail = 'serviceaccount'
pk12File = file('key.p12')
}
play
塊中包含Gradle Play Publisher插件特有的屬性。除了服務(wù)賬號證書策菜,你還可以指定APK的發(fā)布途徑:
play {
track = 'production'
}
默認(rèn)的途徑是alpha
晶疼,你可以修改為beta
或者product
。
Beta分發(fā)
有很多Android app的beta測試又憨,比如Google Play商店的bata途徑翠霍。另一個(gè)是Crashlytics(https://crashlytics.com),與Gradle有很好的集成蠢莺。Crashlytics的團(tuán)隊(duì)創(chuàng)建了這個(gè)自定義的插件寒匙,不僅可以創(chuàng)建新的Gradle任務(wù)來向他們的平臺發(fā)布構(gòu)建,還可以與Android插件任務(wù)掛鉤來操作ProGuard映射躏将。
你可以按照網(wǎng)站的步驟來使用Crashlytics锄弱。設(shè)置好后,它就會與你的構(gòu)建掛鉤祸憋。Crashlytics插件暴露了一個(gè)名為crashlyticsUploadDistributionInternal
的任務(wù)会宪,可以用來將APK上傳到Crashlytics。為了推送一個(gè)新的app版本夺衍,你首先需要使用build
或者assemble
任務(wù)來進(jìn)行構(gòu)建。APK準(zhǔn)備好后喜命,你可以使用crashlyticsUploadDistributionInternal
任務(wù)將它上傳到Crashlytics沟沙。Crashlytics插件為每個(gè)構(gòu)建變體創(chuàng)建了一個(gè)上傳任務(wù)。
自定義Gradle插件使開發(fā)者們可以很容易地使用Crashlytics壁榕,也使你很容易將你的測試構(gòu)建上傳到Crashlytics矛紫,因?yàn)槟阒恍枰跇?gòu)建構(gòu)成中執(zhí)行一個(gè)額外的任務(wù)。這是一個(gè)恰當(dāng)使用Gradle強(qiáng)大之處牌里,以及一個(gè)好的Gradle插件使編程變得簡單的的很好的例子颊咬。