基于Travis CI搭建Android自動打包發(fā)布工作流

最近付費購買了Travis CI爸业,Travis CI的收費模式很有意思,不是按項目或者用戶亏镰,而是按工作進程收費扯旷,比如初級版本是$129/月,總共提供2個工作進程索抓。在項目不多的情況下钧忽,除了用于跑單元測試外,不免想利用的更充分一些逼肯,因此抽空搭建了一套基于Travis CI的Android自動發(fā)布工作流耸黑。

未自動化前安卓開發(fā)總是避免不了這樣的工作流程:

  1. 開發(fā)一些新功能,提交代碼
  2. 完成一部分功能后篮幢,打包一個測試版APK
  3. 將測試版APK上傳到QQ群 / 網(wǎng)盤 / Fir.im / 蒲公英
  4. 在QQ群或發(fā)布平臺解釋當(dāng)前版本所完成的功能
  5. 通知測試人員測試

實現(xiàn)了這套自動化發(fā)布后大刊,工作流程被簡化成:

  1. 開發(fā)新功能,提交代碼
  2. 通過git tag對代碼打一個內(nèi)測版的tag三椿,在tag的描述中對寫當(dāng)前完成的功能

Tag提交后Travis CI會自動編譯代碼缺菌,生成APK文件并分發(fā)到Github和fir.im,Github和fir.im中會保持Tag的描述信息搜锰,分發(fā)完成后會有郵件通知所有參與測試的人員伴郁。而作為開發(fā)人員,只需要專注于對代碼打好一個Tag就可以了蛋叼。

整個流程看似做了不少工作焊傅,其實體現(xiàn)在Travis CI只有數(shù)行指令而已,以下逐一講解:

對安卓項目啟用Travis CI

Travis CI應(yīng)該可以算是目前最好用的持續(xù)集成服務(wù)之一了,如果代碼庫是基于Github的話租冠,可以很簡單的開啟鹏倘。由于本文涉及到了很多Travis CI的基礎(chǔ)概念,建議首先對Travis CI的自定義構(gòu)建一節(jié)有所了解顽爹。

很早前在介紹PHP項目的持續(xù)集成時也寫過如何在PHP項目中使用Travis CI。 對于安卓項目來說步驟幾乎一致:

首先準備一個.travis.yml文件放在安卓項目根目錄下骆姐,.travis.yml中記錄了Travis CI所需的基礎(chǔ)信息:

language: android

sudo: false

android:
  components:
  - build-tools-23.0.1
  - android-23
  - extra-android-m2repository
  - extra-android-support

script:
  - "./gradlew assembleRelease"

無需讀文檔就可以通過上面的配置大概知道镜粤,我們要運行的是一個安卓項目,安卓SDK版本為23玻褪,項目所用的BuildTools版本為23.0.1肉渴,為編譯這個項目我們還引入了一些必須的組件,如Support Library(extra-android-support)带射、Android Support Repository(extra-android-m2repository)等同规。

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

最后進入Travis CI主頁灿里,使用有項目Admin權(quán)限的Github帳號直接登錄关炼。選擇要開啟Travis CI的項目,將右邊的開關(guān)設(shè)為On即可匣吊。

Travis CI目前有2個網(wǎng)站:如果是開源項目儒拂,直接進入travis-ci.org即可,如果是私有付費項目色鸳,則需要進入travis-ci.com社痛,2個網(wǎng)站除了域名外所有的界面及操作幾乎一模一樣。

配置中還有一行sudo: false命雀,是為了開啟基于容器的Travis CI任務(wù)蒜哀,讓編譯效率更高。

安卓自動化構(gòu)建的密碼和證書安全

安卓項目發(fā)布需要證書文件和若干密碼咏雌,但無論是開源項目還是私有項目凡怎,任何時候都不應(yīng)該將原始證書或密碼放入代碼庫(原則上來講證書和密碼也不應(yīng)該交于開發(fā)人員,而應(yīng)該只能通過發(fā)布服務(wù)器進行編譯)赊抖。Travis CI為此提供了2種解決方案统倒,一種是對敏感信息、密碼氛雪、證書等進行對稱加密房匆,在CI構(gòu)建環(huán)境時解密,另一種是將密碼等通過Travis CI的控制臺(即網(wǎng)站)設(shè)置為構(gòu)建時的環(huán)境變量。

由于前者會在Travis控制臺生成一對環(huán)境變量浴鸿,所以我的做法是盡量選擇后者井氢,但由于Travis控制臺無法上傳文件,因此涉及到文件加密的部分岳链,則只能選擇前者花竞。

說了這么多,首先還是需要先對編譯腳本進行改造掸哑,如果不考慮安全問題约急,項目的build.gradle文件可能會是這樣:

android {
    signingConfigs {
        releaseConfig {
            storeFile file("../keys/evandroid.jks")
            storePassword "123456"
            keyAlias "evandroid_alias"
            keyPassword "654321"
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.releaseConfig
        }
    }
}

而我們最終要的效果,還是希望一份編譯腳本既可以用于開發(fā)環(huán)境苗分,也可以在CI環(huán)境下使用厌蔽,在Travis CI中,可以通過點擊項目名稱 -> Settings -> Environment Variables中設(shè)置環(huán)境變量摔癣,比如我們可以針對上面的配置奴饮,分別設(shè)置KEYSTORE_PASSALIAS_NAME择浊、ALIAS_PASS三個環(huán)境變量戴卜,在Travis CI環(huán)境下可以通過System.getenv()獲得這些環(huán)境變量。

本地開發(fā)環(huán)境中近她,我的做法是將這幾個變量加到gradle.properties文件中叉瘩,這樣就可以在build.gradle內(nèi)直接使用了。下面是開發(fā)環(huán)境的gradle.properties

KEYSTORE_PASS=123456
ALIAS_NAME=evandroid_alias
ALIAS_PASS=654321

這樣一來build.gradle就變成了

        releaseConfig {
            storeFile file("../keys/evandroid.jks")
            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")
        }

接下來處理證書文件粘捎,為了方便文件加密等功能薇缅,Travis CI提供了一個基于ruby的CLI命令行工具,可以直接使用gem安裝

gem install travis

安裝后進入安卓項目根目錄攒磨,嘗試對證書文件加密:

travis encrypt-file keys/evandroid.jks --add

如果首次運行泳桦,travis會提示需要登錄,運行travis login --org并輸入Github用戶名密碼即可娩缰。(付費版則為travis login --pro

travis encrypt-file指令會做幾件事情:

  1. 在Travis CI控制臺自動生成一對密鑰灸撰,形如:encrypted_e41864bb9dab_key,encrypted_e41864bb9dab_iv
  2. 基于密鑰通過openssl對文件進行加密,上例中會項目根目錄生成evandroid.jks.enc文件
  3. .travis.yml中自動生成Travis CI環(huán)境下解密文件的配置拼坎,上例運行后可以看到.travis.yml中多了幾行:
before_install:
- openssl aes-256-cbc -K $encrypted_e41864bb9dab_key -iv $encrypted_e41864bb9dab_i -in keys/evandroid.jks.enc -out keys/evandroid.jks -d

Travis CI默認在項目根目錄下運行浮毯,因此注意根據(jù)實際需求調(diào)整enc文件的路徑。

最后別忘了在.gitignore中忽略keys/evandroid.jks以及gradle.properties并在代碼庫中將其刪除泰鸡。

Travis CI自動發(fā)布安卓apk文件到Github Release

Travis CI的script部分運行成功后债蓝,可以通過配置文件進入到發(fā)布階段。下面是一個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

這個例子中配置了這樣一些內(nèi)容:

  • provider:發(fā)布目標為Github Release盛龄,除了Github外饰迹,Travis CI還支持發(fā)布到AWS芳誓、Google App Engine等數(shù)十種provider
  • Github用戶名和密碼,因為Travis CI要上傳APK文件啊鸭,因此需要有Github項目的寫入權(quán)限
  • file: 發(fā)布文件锹淌,輸入文件路徑即可
  • skip_cleanup: 默認情況下Travis CI在完成編譯后會清除所有生成的文件,因此需要將skip_cleanup設(shè)置為true來忽略此操作赠制。
  • on: 發(fā)布的時機赂摆,這里配置為tags: true,即只在有tag的情況下才發(fā)布钟些。

雖然這樣就能完成自動發(fā)布库正,但是直接暴露了Github密碼是我們更加不能接受的。更好的做法是在Github -> settings -> Personal access tokens 生成一個只能訪問當(dāng)前項目并只有讀取權(quán)限的Github Access Token厘唾,并通過Travis CI將Access Token加密。聽起來有點繁瑣龙誊,好在Travis CLI中已經(jīng)可以通過一行指令做好這一切:

travis setup release

根據(jù)提示填寫上述配置項目的信息后抚垃,Travis CLI會自動在.travis.yml文件中生成好所有的配置項:

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。

在運行travis setup release時有可能遇到

Invalid scheme format: git@github.com
for a full error report, run travis report

這樣的報錯趟大,看起來是Travis CLI還不支持通過密鑰訪問Github鹤树,因此可以將項目的源臨時切換為http形式,運行成功后再切換回來:

git remote set-url origin https://github.com/AlloVince/evandroid.git
git remote set-url origin git@github.com:AlloVince/evandroid.git

在實際部署過程中逊朽,發(fā)現(xiàn)發(fā)布到Github Release比較坑的點是

git push
git push --tags

往往會同時生成2個Travis CI任務(wù)罕伯,但是在Travis網(wǎng)頁中默認界面只能看到最后跑的一個任務(wù),而未打Tag的任務(wù)又會報

Skipping a deployment with the releases provider because this is not a tagged commit

這曾讓我一度以為自己的腳本哪里寫錯了叽讳,但是又找不到錯誤原因……

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

自動發(fā)布到Github對于開發(fā)人員已經(jīng)足夠追他,但是考慮到項目實際需要以及國情,還是有必要選擇一個國內(nèi)的App分發(fā)服務(wù)岛蚤,fir.im邑狸、蒲公英都是不錯的選擇,不但允許游客下載涤妒,還提供了二維碼等更適合對接手機的功能单雾,國內(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ā)布成功后通過fir命令行工具將apk上傳到fir贿讹。

其中$FIR_TOKEN可以在fir.im的用戶->API Token中找到渐逃,然后在Travis CI控制臺中創(chuàng)建環(huán)境變量FIR_TOKEN并粘貼即可。

這里有個小技巧围详,如果我們僅僅上傳APK文件到fir.im朴乖,看到鏈接的測試人員其實并不知道這次發(fā)布所包含的變動祖屏,因此通過git cat-file tag $TRAVIS_TAG將當(dāng)前發(fā)布tag所包含的附加信息一同上傳了。其中$TRAVIS_TAG變量是Travis CI每次運行自動附帶的環(huán)境變量买羞,還有很多其他的Travis環(huán)境變量供我們玩出更多花樣袁勺。

發(fā)布完畢后自動發(fā)郵件通知

雖然Travis CI也有通知功能,但不能定制模板畜普,通知內(nèi)容也僅僅為提示CI運行的結(jié)果期丰,顯然更適合開發(fā)人員。我們還是希望最終能以更友好的方式通知團隊成員吃挑,同時考慮到郵件送達率钝荡,可以優(yōu)先選擇如SubmailSendCloud等國內(nèi)郵件發(fā)送服務(wù)舶衬。

這里以Submail為例埠通,首先需要在Submail內(nèi)創(chuàng)建郵件模板,比如我們可以創(chuàng)建這樣一封觸發(fā)式郵件模板:

Hi 親

@var(TRAVIS_REPO_SLUG)新版本@var(TRAVIS_TAG)已經(jīng)發(fā)布了逛犹,功能更新:

@var(TAG_DESCRIPTION)

去下載:
http://fir.im/w13s

創(chuàng)建后可以得到郵件模板id端辱,根據(jù)Submail手冊,將模板中所需要的變量置入虽画,最終可以使用一行Curl指令發(fā)送一封郵件:

after_deploy:- curl -d "appid=10948&to=allo.vince@gmail.com&subject=[自動通知] 安卓新版本$TRAVIS_TAG發(fā)布&project=u2c0r2&signature=$SUBMAIL_SIGN&vars={\"TRAVIS_REPO_SLUG\":\"$TRAVIS_REPO_SLUG\",\"TRAVIS_TAG\":\"$TRAVIS_TAG\",\"TAG_DESCRIPTION\":\"$(git cat-file tag $TRAVIS_TAG | awk 1 ORS='<br>')\"}" https://api.submail.cn/mail/xsend.json

其中Submail用到的認證憑據(jù)signature同樣是通過Travis CI控制臺配置的舞蔽。

總結(jié)

最終完成的示例項目在此。其實所有的yml文件配置不到30行码撰,就能省去繁瑣的日常工作渗柿,何樂而不為呢。最后回顧一下自動化后的日常工作:

提交代碼:

git add .
git commit -m "這里是注釋"
git push origin

打Tag

git tag -a v0.0.1-alpha.1 -m "這里是Tag注釋脖岛,說清楚這個版本的主要改動朵栖,也可以省略-m參數(shù)直接寫長文本"
git push origin --tags

如果發(fā)現(xiàn)打錯了tag,可以刪除本地及遠程tag

git tag -d v0.0.1-alpha.1
git push origin --delete tag v0.0.1-alpha.1

大部分Tag標簽雖然僅用于內(nèi)測鸡岗,但是仍然建議允許版本語義化原則混槐。

References

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市轩性,隨后出現(xiàn)的幾起案子声登,更是在濱河造成了極大的恐慌,老刑警劉巖揣苏,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件悯嗓,死亡現(xiàn)場離奇詭異,居然都是意外死亡卸察,警方通過查閱死者的電腦和手機脯厨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來坑质,“玉大人合武,你說我怎么就攤上這事临梗。” “怎么了稼跳?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵盟庞,是天一觀的道長。 經(jīng)常有香客問我汤善,道長什猖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任红淡,我火速辦了婚禮不狮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘在旱。我一直安慰自己摇零,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布桶蝎。 她就那樣靜靜地躺著遂黍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪俊嗽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天铃彰,我揣著相機與錄音绍豁,去河邊找鬼。 笑死牙捉,一個胖子當(dāng)著我的面吹牛竹揍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播邪铲,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼芬位,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了带到?” 一聲冷哼從身側(cè)響起昧碉,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎揽惹,沒想到半個月后被饿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡搪搏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年狭握,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片疯溺。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡论颅,死狀恐怖哎垦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情恃疯,我是刑警寧澤漏设,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站澡谭,受9級特大地震影響愿题,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蛙奖,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一潘酗、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧雁仲,春花似錦仔夺、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至吹艇,卻和暖如春惰蜜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背受神。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工抛猖, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鼻听。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓财著,卻偏偏與公主長得像,于是被迫代替她去往敵國和親撑碴。 傳聞我的和親對象是個殘疾皇子撑教,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,573評論 2 353

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