基于Travis CI搭建Android持續(xù)集成以及自動(dòng)打包發(fā)布流程

前言

最近項(xiàng)目進(jìn)度比較輕松罗丰,閑來(lái)自己研究一些感興趣的技術(shù)男韧,恰好這兩天研究了一下Travic CI, 用于Android持續(xù)集成以及自動(dòng)打包涝涤,話不多說(shuō)句占,下面大家就跟我一起踏入Travis CI的奇妙旅行

背景

我們?cè)陂_(kāi)發(fā)Android項(xiàng)目的時(shí)候舔腾,大致的流程是這樣:


image

Question:這些步驟能否簡(jiǎn)化溪胶,能否自動(dòng)化?
懶是碼農(nóng)的美德稳诚,作為資深碼農(nóng)應(yīng)該善于用工具提高自己的工作效率哗脖,能自動(dòng)化的要自動(dòng)化。那么今天要講的Travis CI就能簡(jiǎn)化我們的工作扳还,上述流程如果使用Travis CI那么工作流程是這樣的:

image

Tag提交后才避,Travis CI會(huì)自動(dòng)編譯代碼,生成apk文件普办,并發(fā)到Github和相應(yīng)地其他渠道(fir.im, 蒲公英等)工扎,分發(fā)完成后,會(huì)郵件通知參與測(cè)試的人員衔蹲。如此一來(lái)肢娘,作為碼農(nóng),只要安心Coding和打Tag就好了舆驶,輕松愉快啊??,下面我們就來(lái)著重介紹Travis

什么是Travis CI

簡(jiǎn)單來(lái)說(shuō)它是用來(lái)做持續(xù)集成的工具橱健,可以為你自動(dòng)構(gòu)建、測(cè)試沙廉、打包等等拘荡,極大的簡(jiǎn)化了工作流程。它對(duì)Github的支持特別好撬陵,鏈接到你在Github上的項(xiàng)目以后珊皿,每當(dāng)你把測(cè)試通過(guò)后的代碼提交到master去,它會(huì)pull你的代碼并按照你的要求構(gòu)建執(zhí)行

如何安裝Travis CI

首先需要安裝Ruby, 你可以通過(guò)運(yùn)行ruby -v 檢查系統(tǒng)是否安裝Ruby:

$ ruby -v
ruby 2.0.0p645 (2015-04-13 revision 50299) [universal.x86_64-darwin15]

然后運(yùn)行:

$ gem install travis -v 1.8.0 --no-rdoc --no-ri

安裝完畢后巨税,檢驗(yàn)一下:

$ travis version
1.8.0

配置Android項(xiàng)目蟋定,啟用Travis CI

先添加Travis CI到Github repo:

image

然后按照官網(wǎng)說(shuō)法是大致三步走:

image

先選擇要開(kāi)啟Travis CI的項(xiàng)目,將開(kāi)關(guān)設(shè)為On即可:

image

在項(xiàng)目的根目錄下新建一個(gè)文件.travis.yml草添,如下是一個(gè)Android 項(xiàng)目的配置模板:

language: android
android:
  components:
    # Uncomment the lines below if you want to
    # use the latest revision of Android SDK Tools
    # - platform-tools
    # - tools
    # The BuildTools version used by your project
    - build-tools-19.1.0
    # The SDK version used to compile your project
    - android-19
    # Additional components
    - extra-google-google_play_services
    - extra-google-m2repository
    - extra-android-m2repository
    - addon-google_apis-google-19
    # Specify at least one system image,
    # if you need to run emulator(s) during your tests
    - sys-img-armeabi-v7a-android-19
    - sys-img-x86-android-17

當(dāng)Travis CI準(zhǔn)備好我們所需要的環(huán)境后驶兜,將自動(dòng)運(yùn)行yml文件script部分所設(shè)置的指令,上例中運(yùn)行的是./gradlew assembleRelease,運(yùn)行成功的話會(huì)在項(xiàng)目的主模塊下生成build/outputs/apk/app-release.apk

【備注】Travis CI目前有2個(gè)網(wǎng)站:如果是開(kāi)源項(xiàng)目抄淑,直接進(jìn)入travis-ci.org即可屠凶,如果是私有付費(fèi)項(xiàng)目,則需要進(jìn)入travis-ci.com肆资,2個(gè)網(wǎng)站除了域名外所有的界面及操作幾乎一模一樣

Android項(xiàng)目自動(dòng)化構(gòu)建的密碼和證書(shū)安全問(wèn)題

安卓項(xiàng)目發(fā)布需要證書(shū)文件和若干密碼矗愧,但無(wú)論是開(kāi)源項(xiàng)目還是私有項(xiàng)目,任何時(shí)候都不應(yīng)該將原始證書(shū)或密碼放入代碼庫(kù)(原則上來(lái)講證書(shū)和密碼也不應(yīng)該交于開(kāi)發(fā)人員迅耘,而應(yīng)該只能通過(guò)發(fā)布服務(wù)器進(jìn)行編譯)贱枣。Travis CI為此提供了2種解決方案,一種是對(duì)敏感信息颤专、密碼、證書(shū)等進(jìn)行對(duì)稱加密钠乏,在CI構(gòu)建環(huán)境時(shí)解密栖秕,另一種是將密碼等通過(guò)Travis CI的控制臺(tái)(即網(wǎng)站)設(shè)置為構(gòu)建時(shí)的環(huán)境變量。

由于前者會(huì)在Travis控制臺(tái)生成一對(duì)環(huán)境變量晓避,所以我的做法是盡量選擇后者簇捍,但由于Travis控制臺(tái)無(wú)法上傳文件,因此涉及到文件加密的部分俏拱,則只能選擇前者暑塑。
說(shuō)了這么多,首先還是需要先對(duì)編譯腳本進(jìn)行改造锅必,如果不考慮安全問(wèn)題事格,項(xiàng)目的build.gradle文件可能會(huì)是這樣:

android {
    signingConfigs {
        releaseConfig {
            storeFile file("../xx.keystore")
            storePassword "123456"
            keyAlias "key_alias"
            keyPassword "123456"
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.releaseConfig
        }
    }
}

而我們最終要的效果,還是希望一份編譯腳本既可以用于開(kāi)發(fā)環(huán)境搞隐,也可以在CI環(huán)境下使用驹愚,在Travis CI中,可以通過(guò)點(diǎn)擊項(xiàng)目名稱 -> Settings -> Environment Variables中設(shè)置環(huán)境變量劣纲,比如我們可以針對(duì)上面的配置逢捺,分別設(shè)置KEYSTORE_PASS、ALIAS_NAME癞季、ALIAS_PASS三個(gè)環(huán)境變量:

image

在Travis CI環(huán)境下可以通過(guò)System.getenv()獲得這些環(huán)境變量
本地開(kāi)發(fā)環(huán)境中劫瞳,我的做法是將這幾個(gè)變量加到gradle.properties文件中,這樣就可以在build.gradle內(nèi)直接使用了绷柒。下面是開(kāi)發(fā)環(huán)境的gradle.properties:

KEYSTORE_PASS=123456
ALIAS_NAME=key_alias
ALIAS_PASS=123456

這樣一來(lái)build.gradle就變成了:

releaseConfig {
            storeFile file("../xx.keystore")
            storePassword project.hasProperty("KEYSTORE_PASS") ? KEYSTORE_PASS : System.getenv("KEYSTORE_PASS")
            keyAlias project.hasProperty("ALIAS_NAME") ? ALIAS_NAME : System.getenv("ALIAS_NAME")
            keyPassword project.hasProperty("ALIAS_PASS") ? ALIAS_PASS : System.getenv("ALIAS_PASS")
        }

接下來(lái)處理證書(shū)文件志于,為了方便文件加密等功能,Travis CI提供了一個(gè)基于ruby的CLI命令行工具辉巡,可以直接使用gem安裝:

gem install travis

安裝后進(jìn)入安卓項(xiàng)目根目錄恨憎,嘗試對(duì)證書(shū)文件加密:

travis encrypt-file xx.keystore --add

travis encrypt-file指令會(huì)做幾件事情:
1.在Travis CI控制臺(tái)自動(dòng)生成一對(duì)密鑰: encrypted_59c5087c0788_keyencrypted_59c5087c0788_iv

image

2.基于密鑰通過(guò)openssl對(duì)文件進(jìn)行加密,上例中會(huì)項(xiàng)目根目錄生成xx.keystore.enc文件
3.在.travis.yml中自動(dòng)生成Travis CI環(huán)境下解密文件的配置,上例運(yùn)行后可以看到.travis.yml中多了幾行:

before_install:
- gem install fir-cli
- openssl aes-256-cbc -K $encrypted_59c5087c0788_key -iv $encrypted_59c5087c0788_iv
  -in xx.keystore.enc -out xx.keystore -d

最后在.gitignore中忽略xx.keystore以及gradle.properties

Travis Ci自動(dòng)發(fā)布安裝apk文件到Github Release

Travis CI的script部分運(yùn)行成功后憔恳,可以通過(guò)配置文件進(jìn)入到發(fā)布階段瓤荔。下面是一個(gè)Travis CI發(fā)布的示例:

deploy:
  provider: releases
  user: "GITHUB USERNAME"
  password: "GITHUB PASSWORD"
  file: app/build/outputs/apk/app-release.apk
  skip_cleanup: true
  on:
    tags: true
  • provider:發(fā)布目標(biāo)為Github Release
  • Github用戶名和密碼,因?yàn)門(mén)ravis CI要上傳APK文件钥组,因此需要有Github項(xiàng)目的寫(xiě)入權(quán)限
  • file: 發(fā)布文件输硝,輸入文件路徑即可
  • skip_cleanup: 默認(rèn)情況下Travis CI在完成編譯后會(huì)清除所有生成的文件,因此需要將skip_cleanup設(shè)置為true來(lái)忽略此操作程梦。
  • on: 發(fā)布的時(shí)機(jī)点把,這里配置為tags: true,即只在有tag的情況下才發(fā)布屿附。

這邊直接暴露了Github密碼是我們更加不能接受的郎逃。更好的做法是在Github -> settings -> Personal access tokens 生成一個(gè)只能訪問(wèn)當(dāng)前項(xiàng)目并只有讀取權(quán)限的Github Access Token,并通過(guò)Travis CI將Access Token加密挺份。好在Travis CLI中已經(jīng)可以通過(guò)一行指令做好這一切:

travis setup release

根據(jù)提示填寫(xiě)上述配置項(xiàng)目的信息后褒翰,Travis CLI會(huì)自動(dòng)在.travis.yml文件中生成好所有的配置項(xiàng):

deploy:
  provider: releases
  api_key:
    secure: XXX
  file: app/build/outputs/apk/app-release.apk
  skip_cleanup: true
  on:
    tags: true
    all_branches: true

其中api_key下的secure就是加密后的Access Token。

自動(dòng)發(fā)布APK到fir.im

自動(dòng)發(fā)布到Github對(duì)于開(kāi)發(fā)人員已經(jīng)足夠匀泊,但是考慮到項(xiàng)目實(shí)際需要以及國(guó)情优训,還是有必要選擇一個(gè)國(guó)內(nèi)的App分發(fā)服務(wù),fir.im是不錯(cuò)的選擇各聘,不但允許游客下載揣非,還提供了二維碼等更適合對(duì)接手機(jī)的功能,國(guó)內(nèi)下載速度也很快躲因。由于fir.im提供了比較方便的CLI工具早敬,因此本文以fir.im為例,在.travis.yml中添加以下幾行:

before_install:
- gem install fir-cli
after_deploy:
- fir p app/build/outputs/apk/app-release.apk -T $FIR_TOKEN -c "`git cat-file tag $TRAVIS_TAG`"

即在環(huán)境構(gòu)建階段安裝fir-cli毛仪,在發(fā)布成功后通過(guò)fir命令行工具將apk上傳到fir搁嗓。
其中$FIR_TOKEN可以在fir.im的用戶->API Token中找到,然后在Travis CI控制臺(tái)中創(chuàng)建環(huán)境變量FIR_TOKEN并粘貼即可箱靴。

image

總結(jié)

其實(shí)所有的yml文件配置不到30行腺逛,就能利用Travis CI進(jìn)行自動(dòng)化持續(xù)集成和打包。最后我們回顧一下Travis CI的工作流:
提交代碼:

git add .
git commit -m "注釋"
git push origin

打Tag:

git tag -a v0.0.1-alpha.1 -m "Tag注釋衡怀,說(shuō)清楚這個(gè)版本的主要改動(dòng)棍矛,也可以省略-m參數(shù)直接寫(xiě)長(zhǎng)文本"
git push origin --tags

這個(gè)是我集成了Travis CI的項(xiàng)目地址,供參考:
https://github.com/archmages/DYWeather

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末抛杨,一起剝皮案震驚了整個(gè)濱河市够委,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌怖现,老刑警劉巖茁帽,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件玉罐,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡潘拨,警方通過(guò)查閱死者的電腦和手機(jī)吊输,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)铁追,“玉大人季蚂,你說(shuō)我怎么就攤上這事±攀” “怎么了扭屁?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)涩禀。 經(jīng)常有香客問(wèn)我料滥,道長(zhǎng),這世上最難降的妖魔是什么埋泵? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任幔欧,我火速辦了婚禮,結(jié)果婚禮上丽声,老公的妹妹穿的比我還像新娘。我一直安慰自己觉义,他們只是感情好雁社,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著晒骇,像睡著了一般霉撵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上洪囤,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天徒坡,我揣著相機(jī)與錄音,去河邊找鬼瘤缩。 笑死喇完,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的剥啤。 我是一名探鬼主播锦溪,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼府怯!你這毒婦竟也來(lái)了刻诊?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤牺丙,失蹤者是張志新(化名)和其女友劉穎则涯,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡粟判,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年亿昏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片浮入。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡龙优,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出事秀,到底是詐尸還是另有隱情彤断,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布易迹,位于F島的核電站宰衙,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏睹欲。R本人自食惡果不足惜供炼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望窘疮。 院中可真熱鬧袋哼,春花似錦、人聲如沸闸衫。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蔚出。三九已至弟翘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間骄酗,已是汗流浹背稀余。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留趋翻,地道東北人睛琳。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像嘿歌,于是被迫代替她去往敵國(guó)和親掸掏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

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