詳解Android的自動化構(gòu)建及發(fā)布
在一個App從開發(fā)到測試的過程中,我有很長一段時間都是這樣做的:打包,上傳到tower,在tower上編寫本次更新說明,通知測試。一般情況下,打包及上傳的過程大概也就2分鐘。除此之外,由于項(xiàng)目代碼有作混淆,并且使用了bugly,因此在發(fā)出每個版本之后還需要將混淆的mapping.txt傳到bugly上。當(dāng)日復(fù)一日,并且有時還遇到網(wǎng)絡(luò)較差的情況時,這種人工手動的工作方式就很影響工作效率及心情了。因此,自動化構(gòu)建及發(fā)布就成了必須掌握的技能了。
本篇分享的是我在Android自動化構(gòu)建的一些經(jīng)驗(yàn),涉及到的工具及網(wǎng)站如下:
- Gradle
- fir.im
- Gitlab
- gitlab-ci-multi-runner
所述內(nèi)容包含:
- 使用Gradle自動構(gòu)建并發(fā)布到fir
- 使用Gitlab-CI,在提交時自動化構(gòu)建并發(fā)布到fir
- 在服務(wù)器配置Docker版的gitlab-ci-multi-runner
- 多flavor時,在fir上同時發(fā)布的解決方案
Gradle及fir帶來的解放生產(chǎn)力
構(gòu)建并上傳apk到fir
我接觸fir.im的時間比較早,那時官方就已經(jīng)提供了一個命令行打包并上傳的工具fir-cli。但是有兩個問題是我難以忍受的:
1. 它需要安裝,并且由于使用ruby編寫,所以還需要ruby環(huán)境
2. 它會構(gòu)建所有flavor的版本,雖然最后只上傳一個(該問題后來已經(jīng)解決)
于是,在發(fā)現(xiàn)它有提供API之后,我查閱了下Gradle的文檔,自己寫了一個簡單的fir發(fā)布插件——fir-publish。
這個插件很小很輕,沒有使用額外依賴庫,網(wǎng)絡(luò)請求使用的也是Gradle本身就有的http-client的API。使用方式如下:
首先在根項(xiàng)目的build.gradle中加入以下依賴:
buildscript { repositories { jcenter() } dependencies { classpath 'com.githang:fir:0.1.6' } }
然后在app里的build.gradle文件末尾加入以下配置:
apply plugin: 'fir' fir { apiToken //fir.im上的API token bundleId android.defaultConfig.applicationId flavor "Test" (如果沒有productFlavor,可不配置此項(xiàng)),僅在上傳apk時需要 appName 你的應(yīng)用名稱,僅在上傳apk時需要 icon 應(yīng)用圖標(biāo)路徑,僅在上傳圖標(biāo)時需要 changeLog "更新日志" // 或者使用 file("日志文件路徑") }
其中的API token在你登錄fir之后,點(diǎn)擊自己的賬號就可以獲取。
該插件向你的project添加以下4個任務(wù):
- firCert 獲取上傳憑證
- firIcon 上傳圖標(biāo),依賴于firCert
- firApk 上傳APK,依賴于firCert及assembleRelease(或assembleFlavorRelease)
- firAll 上傳圖標(biāo)及APK,依賴于firIcon及firApk
在上面的配置中,更新日志可以直接寫在上面,也可以單獨(dú)創(chuàng)建一個更新日志的文件(推薦),每次要發(fā)布時只需要修改這個文件上的更新日志,然后執(zhí)行以下命令即可自動構(gòu)建并發(fā)布到fir:
./gradlew firAll
注:windows用戶在前面不需要加./
這樣,我們只需要讓測試人員關(guān)注fir上的更新動態(tài)即可,而不必自己去等待構(gòu)建完成再上傳然后等待上傳完成再去寫更新日志。
構(gòu)建時上傳mapping.txt到bugly
關(guān)于自動上傳mapping.txt到bugly的問題,其實(shí)bugly本身已有提供相關(guān)的Gradle插件bugly。但是它會在每次構(gòu)建Release版本中都執(zhí)行上傳mapping.txt,而通常我們只是在最終打包版本給測試的時候才需要,所以我修改了一下配置:
def isPublish = hasProperty("publish") bugly { appId = '你的appId' appKey = '你的appKey' execute = isPublish upload = isPublish }
在這里新增加了一個變量 ,僅在有publish屬性時才執(zhí)行上傳的命令,這個屬性在執(zhí)行的時候帶入,因此我們打包并發(fā)布的命令將進(jìn)一步演變?yōu)槿缦拢?/p>
./gradlew firApk -Ppublish
Gitlab-CI帶來的進(jìn)一步解放
在上面的過程中,其實(shí)我們解決的最大問題是把構(gòu)建——發(fā)布——編寫版本更新日志這三個步驟合成一步,少去了中間過程的等待,但是結(jié)果還是我們要在每次需要時去手動執(zhí)行這一步。
CI類的服務(wù)能夠讓我們把代碼推送到服務(wù)器上時即可開始構(gòu)建,使得我們的整個構(gòu)建過程達(dá)到真正的自動化,而不用人工參與。
由于公司使用的是Gitlab,所以這里只談Gitlab-CI相關(guān)的內(nèi)容。
新版的Gitlab CI中使用的是gitlab-ci-multi-runner,關(guān)于它的安裝可以到參考其官方文檔,這里不再贅述。
需要注意一點(diǎn)的是,在安裝之后進(jìn)行注冊時,如果你是想注冊為共享runner(所有項(xiàng)目都可使用),那么第一個問題的地址應(yīng)該是你們公司gitlab的地址,第二個問題的token在管理員界面的runner配置中可以看到。如果是想注冊為私有的runner,則其url與token在項(xiàng)目的設(shè)置中可以看到。
接下來,只需要在我們的項(xiàng)目的根目錄中添加一個.gitlab-ci.yml文件,并在其中進(jìn)行CI配置,然后提交并推送到我們的gitlab上即可。
還是以我這里的公司項(xiàng)目為例。項(xiàng)目采用Git-flow流程進(jìn)行開發(fā),在要發(fā)布時會創(chuàng)建release分支,因此需要發(fā)布到fir上給測試人員的是release分支及tag上的代碼,其他分支的代碼我們只需要進(jìn)行構(gòu)建測試就可以了。在我們公司的項(xiàng)目中,有開發(fā)環(huán)境 、測試環(huán)境及生產(chǎn)環(huán)境,分別對應(yīng)三個productFlavor:Develop, Test,Official,它們之間只有API的地址不同。因此,構(gòu)建測試使用其中一個環(huán)境的就可以了。
所以腳本如下:
before_script: - chmod +x ./gradlew compileTest: script: "./gradlew clean aDevelopDebug" except: - /^release.*$/ - tags publishToFir: script: "./gradlew clean firApk -Ppublish" type: deploy only: - /^release.*$/ - tags
在這里,我定義了兩個ci任務(wù),分別是compileTest以及publishToFir。script表示該任務(wù)所執(zhí)行的命令。except表示不對哪些分支進(jìn)行構(gòu)建。使用git-flow流程時,將發(fā)布的分支都是以release/xxx來命名,所以這里用正則來表示。only表示僅對哪些分支執(zhí)行這個構(gòu)建任務(wù)。type表示任務(wù)的類型。
將配置提交,然后推送到Gitlab上,就能夠觸發(fā)CI去執(zhí)行我們所定義的構(gòu)建任務(wù)了。如果你成功了配置了Gitlab上的郵箱發(fā)送服務(wù),那么我們就可以不用主動去關(guān)心這個結(jié)果,因?yàn)槿绻麡?gòu)建失敗了,Gitlab將會向我們發(fā)送郵件通知。
如果你不想使用docker來運(yùn)行runner,可跳過下面這一節(jié)。
如果你也不需要同時在fir上發(fā)布不同flavor的APK,那么后面的也不用看了。
更高級的Docker版的CI Runner
上面雖然使用了gitlab-ci-multi-runner來完成自動化,但是它是在我本機(jī)上跑的。每次編譯時占用的內(nèi)存及CPU會對開發(fā)略有影響,并且還需要我在每次開機(jī)后開個終端運(yùn)行一下這個runner。公司內(nèi)部是有一臺Ubuntu服務(wù)器專門用于代碼及項(xiàng)目相目的服務(wù)的,如果把我們的runner部署到這臺服務(wù)器上那就更好了。
公司的這臺服務(wù)器安裝了Docker,其他的服務(wù)都是以docker形式運(yùn)行的。既然這樣,我也遵守規(guī)則用docker部署上runner吧。
向公司的技術(shù)大伽問來內(nèi)部服務(wù)器的管理員賬號,又翻了一遍《Docker — 從入門到實(shí)踐》的PDF,然后就開始寫Dockerfile并在自己電腦上試驗(yàn)了。
在踩了ubuntu版本安裝不了JDK8、掛載Android SDK目錄、沒有32位動態(tài)庫導(dǎo)致Android SDK執(zhí)行不了,以及中文亂碼等坑之后,目前我的Dockerfile如下:
FROM ubuntu:15.04 MAINTAINER HuangHaohang <msdx.android@qq.com> ENV ANDROID_HOME /android-sdk RUN apt update && apt install -y openjdk-8-jdk curl #如果遇到android-sdk里的命令無法執(zhí)行,則需要安裝32位的動態(tài)鏈接庫。 RUN apt install -y libc6-i386 lib32stdc++6 lib32gcc1 lib32ncurses5 lib32z1 RUN curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-ci-multi-runner/script.deb.sh | bash RUN apt-get install -y gitlab-ci-multi-runner # Ensure UTF-8 locale #COPY locale /etc/default/locale RUN locale-gen zh_CN.UTF-8 && \ DEBIAN_FRONTEND=noninteractive dpkg-reconfigure locales RUN locale-gen zh_CN.UTF-8 ENV LANG zh_CN.UTF-8 ENV LANGUAGE zh_CN:zh ENV LC_ALL zh_CN.UTF-8
注:后續(xù)如果有變化,將在我的github項(xiàng)目上更新,地址為:https://github.com/msdx/dockerfile/blob/master/gitlab-ci-multi-runner/Dockerfile
然后執(zhí)行docker build創(chuàng)建docker鏡像之后,運(yùn)行docker時掛載上android sdk以及可讀寫的gradle緩存目錄就可以了,其他問題包括runner的注冊等可參見我這里的項(xiàng)目說明:https://github.com/msdx/dockerfile/tree/master/gitlab-ci-multi-runner 。由于篇幅原因,這里不作贅述。
我這里把a(bǔ)ndroid-sdk打包并通過ssh上傳到了服務(wù)器,然后解壓在了公司的用戶目錄的android-sdk下,并在該目錄創(chuàng)建了一個文件夾GradleUserHome,用于放Gradle的緩存,最終啟動這個docker的腳本如下:
#!/bin/bash sudo docker run -d \ --name gitlab-ci-multi-runner \ --restart always \ -v /home/irain/android-sdk:/android-sdk:ro \ -v /home/irain/GradleUserHome:/root/.gradle:rw \ irain/gitlab-runner:registered \ gitlab-ci-multi-runner --debug run
fir上的小技巧——多flavor的發(fā)布方式
前面提到我們公司的項(xiàng)目API地址是有分多個環(huán)境的(開發(fā)環(huán)境、測試環(huán)境以及生產(chǎn)環(huán)境)。本來我只需要打包測試環(huán)境的給測試人員用,生產(chǎn)環(huán)境在最終要發(fā)布的時候再自己打包。但是在這次新版本的開發(fā)中,服務(wù)端的人員也希望我能夠打包開發(fā)環(huán)境的Apk給他,這樣有時候他也可以自測一下。由于項(xiàng)目正在開發(fā)中,版本變化較快,所以我也想到通過自動構(gòu)建發(fā)布到fir上,再由他自己去下載,這樣就可保證他可以獲得最新開發(fā)的版本。
然而,相當(dāng)沮喪的一點(diǎn)是,fir上并不支持同一個應(yīng)用多環(huán)境的發(fā)布,雖然這個需求在一年以前就有其他人提出。我問了客服,客服的建議是換一個bundleId(applicationId),當(dāng)然這是不可能的,因?yàn)槲覀兊膽?yīng)用使用到了高德地圖、微信分享及各種支付等許多和applicationId關(guān)聯(lián)的SDK,不可能重新部署一套。最后查看其他人分享的一個實(shí)現(xiàn)技巧。
首先,你需要在fir上注冊一個號(當(dāng)然你也可以請你同事幫忙),然后把你的應(yīng)用上傳上去,再進(jìn)入應(yīng)用的權(quán)限控制,把你的大號邀請進(jìn)來,這樣你的大號上就有兩個這樣的應(yīng)用了,并且可以對它上傳新版本來更新。當(dāng)然,如果你使用API來上傳,則不需要邀請,只需要填不同的API Token即可。所以最終,我的app的build.gradle中關(guān)于fir發(fā)布的配置如下:
def envFlavor = hasProperty("flavor") ? getProperty("flavor") : "Test" if (envFlavor == "Develop") { fir { apiToken "小號的api token" bundleId android.defaultConfig.applicationId flavor envFlavor appName "XXX-開發(fā)版" changeLog "git show -s --format=%B HEAD".execute().text } } else { fir { apiToken "大號的api token" bundleId android.defaultConfig.applicationId flavor envFlavor appName "XXX-測試版" changeLog file("./changeLog.txt") } }
其中,flavor是通過定義的envFlavor來設(shè)置,而envFlavor根據(jù)執(zhí)行的時候傳入的flavor屬性的值來設(shè)置。對應(yīng)的.gitlab-ci.yml也修改如下:
before_script: - chmod +x ./gradlew compileTest: script: "./gradlew clean firApk -Ppublish -Pflavor=Develop" except: - /^release.*$/ - tags publishToFir: script: "./gradlew clean firApk -Ppublish" type: deploy only: - /^release.*$/ - tags
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android onCreateOptionsMenu的使用方法總結(jié)
這篇文章主要介紹了Android onCreateOptionsMenu的使用方法總結(jié)的相關(guān)資料,在Android下,每一個activity都捆綁了一個Menu,要想定義和使用菜單,都必須在Activity下進(jìn)行操作,需要的朋友可以參考下2017-08-08Android遠(yuǎn)程服務(wù)編寫和調(diào)用教程
這篇文章主要介紹了Android遠(yuǎn)程服務(wù)編寫和調(diào)用教程,本文教大家如何編寫或者調(diào)用Android的遠(yuǎn)程服務(wù),感興趣的小伙伴們可以參考一下2016-02-02Android中傳遞對象的三種方法的實(shí)現(xiàn)
本篇文章主要介紹了Android中傳遞對象的三種方法的實(shí)現(xiàn),可以通過Bundle、Intent或者JSON字符串,有興趣的可以了解一下。2017-02-02Android SQLite數(shù)據(jù)庫進(jìn)行查詢優(yōu)化的方法
這篇文章主要給大家介紹了關(guān)于Android SQLite數(shù)據(jù)庫進(jìn)行查詢優(yōu)化的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-11-11Android 實(shí)現(xiàn)自定義圓形進(jìn)度條的實(shí)例代碼
進(jìn)度條在Android中教程使用到,本文章向大家介紹一下Android自定義圓形進(jìn)度條實(shí)現(xiàn)代碼,需要的朋友可以參考一下。2016-11-11Android組合控件實(shí)現(xiàn)功能強(qiáng)大的自定義控件
這篇文章主要介紹了Android組合控件實(shí)現(xiàn)功能強(qiáng)大的自定義控件的相關(guān)資料,需要的朋友可以參考下2016-05-05android RecyclerView側(cè)滑菜單,滑動刪除,長按拖拽,下拉刷新上拉加載
本篇文章主要介紹了android RecyclerView側(cè)滑菜單,滑動刪除,長按拖拽,下拉刷新上拉加載,非常具有實(shí)用價值,需要的朋友可以參考下。2017-03-03