安卓 DevOps:從一次推送命令到生產(chǎn)

DevOps 是一種廣為人知的活動乞旦,其主要目的是使軟件交付自動化贼穆。的確题山,DevOps 的目標(biāo)是持續(xù)測試、代碼質(zhì)量故痊、功能開發(fā)和更輕松地進(jìn)行維護(hù)更新顶瞳。因此,DevOps 的終極目標(biāo)之一是讓開發(fā)者可以執(zhí)行快速可靠愕秫、自動化的發(fā)布慨菱,理想狀態(tài)下,整個流程都不需要人為操作戴甩。這被稱為持續(xù)交付符喝。撰寫本文的目的是展示我們現(xiàn)在也能在安卓上實(shí)現(xiàn)這一目標(biāo),同時分享筆者的想法和反饋意見甜孤。

以持續(xù)集成為起點(diǎn)

為了實(shí)現(xiàn)持續(xù)交付协饲,必須確保強(qiáng)大的持續(xù)集成。這已經(jīng)在安卓環(huán)境實(shí)行一段時間了缴川,但是為了清楚起見茉稠,咱們還是回顧一下吧。

首先把夸,任何安卓應(yīng)用程序都應(yīng)具備持續(xù)集成而线。是的,筆者就是這個意思恋日。實(shí)際上膀篮,這為現(xiàn)代應(yīng)用程序開發(fā)帶來了不可忽視的幾個好處。在筆者看來岂膳,最大的優(yōu)點(diǎn)是以下幾項(xiàng):

  • 構(gòu)建自動化:告別“但是在我的機(jī)器上可以構(gòu)建成功”誓竿。應(yīng)用程序在哪里都能構(gòu)建。

  • 盡早試錯:每次推送后都進(jìn)行構(gòu)建可以確保盡早發(fā)現(xiàn)錯誤闷营。

  • 測試持續(xù)化:確保測試始終進(jìn)行

  • 持續(xù)打包:在打包二進(jìn)制代碼時避免人為錯誤烤黍。

  • 發(fā)布速度更快:因?yàn)槲覀儗γ恳徊綐?gòu)建都有信心知市,發(fā)布也變得更加簡單。

  • 信心增強(qiáng):終于速蕊,我們可以信任自己的代碼和流程嫂丙,并且減少意料之外的錯誤。

典型的持續(xù)集成過程

First, we need an integration server like Jenkins or Travis. The following jobs are my standard configuration:

首先规哲,我們需要一個 Jenkins 或者 Travis 那樣的集成服務(wù)器跟啤。以下作業(yè)是筆者的標(biāo)準(zhǔn)配置:

? 一旦源碼存儲庫(Git、SVN等等)中的推送完成唉锌,就會開始一個作業(yè)隅肥。它會查看 dev 分支、編譯代碼袄简、運(yùn)行單元測試腥放,并打包調(diào)試 APK。

? 第一個作業(yè)成功完成后绿语,運(yùn)行下一個作業(yè)秃症。它會運(yùn)行集成測試(通過Espresso 或 Robotium),通過重現(xiàn)場景和檢查圖像內(nèi)容來確保用戶體驗(yàn)吕粹。你可以使用連接設(shè)備(如果你的 CI 服務(wù)器不容易獲取的話种柑,就有些困難)、Genymotion 或隨 Android Studio 2.0 發(fā)布的最新內(nèi)置模擬器(快去試試吧Fジ)來操作聚请。

? 一個作業(yè)會運(yùn)行代碼測量(舉個例子,通過 Sonarqube)以監(jiān)測代碼質(zhì)量稳其。例如驶赏,筆者會在每天半夜運(yùn)行這個作業(yè)。

? 最后欢际,在我們推送 master 分支或發(fā)布分支后運(yùn)行一個作業(yè)母市。它會編譯代碼,并生成發(fā)布 APK损趋。

好啦患久!如你所見,操作非常簡單浑槽,而且能保證筆者之前列舉的所有優(yōu)點(diǎn)蒋失。

測試是關(guān)鍵

筆者曾寫過一篇關(guān)于安卓測試的文章。測試非常重要桐玻,因?yàn)樗悄茏詣幼C明我們的應(yīng)用按計(jì)劃運(yùn)行的唯一方法篙挽。有很多工具可以幫我們寫出優(yōu)秀的測試代碼,所以要明智地進(jìn)行選擇镊靴。

同時铣卡,在選擇集成到應(yīng)用中的函數(shù)庫時要實(shí)事求是链韭。實(shí)際上,你應(yīng)該明白如果函數(shù)庫的測試覆蓋率較高煮落,測試應(yīng)用程序就會更輕松敞峭。他們已經(jīng)考慮到如何正確測試和通過測試促進(jìn)開發(fā)的問題了(IMO、OkHttpRetrofit 都是很好的范例)蝉仇。相當(dāng)于你在使用的同時就進(jìn)行了測試旋讹。

最后,類似 Dagger 的函數(shù)庫可以增加可測試性轿衔。實(shí)際上沉迹,它會迫使你遵照單一職責(zé)原則,并且將代碼正確分離害驹,這樣測試就更加容易鞭呕。

一旦你擁有了強(qiáng)大的持續(xù)集成,我們來看看怎么升級吧裙秋。

持續(xù)交付:無限升級

舉個例子琅拌,在 Captain Train缨伊,我們每6周發(fā)布一個新版本摘刑,并且對此非常謹(jǐn)慎。目前:

? We have a beta phase.
? We support 4 locales.
? We support 3 types of device (phone, 7 and 9 inches tablets).
? We always check our Play Store listings.
? We create release notes.
? We use the rollout feature.
? We upload our 72 screenshots (6 screenshots * 4 locales * 3 types)
? We have a wear companion.

  • 我們有一個測試階段刻坊。
  • 我們支持4 種語言環(huán)境枷恕。
  • 我們支持3種設(shè)備(手機(jī)、7寸和9寸平板電腦)谭胚。
  • 我們時刻關(guān)注在谷歌電子市場的排名徐块。
  • 我們創(chuàng)建發(fā)布說明。
  • 我們采用發(fā)布功能灾而。
  • 我們上傳72張截圖(6種截圖X4中語言環(huán)境X3中設(shè)備類型)胡控。
  • 我們有一個穿戴伴侶。

這個流程需要花時間旁趟,而且不止一點(diǎn)兒昼激。最近,我們決定是時候嘗試把這個流程自動化了锡搜。雖然主要目的是為了減少發(fā)布版本需要的時間橙困,但是如果同時也能避免人為錯誤,保持各個發(fā)布版本之間的連貫性耕餐,就更好了凡傅。這也讓我們擔(dān)負(fù)了重大的責(zé)任,因?yàn)殚_發(fā)者控制了整個發(fā)布流程肠缔。實(shí)際上夏跷,市場和傳播團(tuán)隊(duì)也要跟我們一起看看怎么將他們的變化集成到發(fā)布版本中去哼转。

但是坦白說……在安卓,開發(fā)者并不能控制所有的事情槽华。谷歌可以释簿。但是,它提供了 HTTP API硼莽,使開發(fā)者輕易地與谷歌電子商店控制臺互動萧朝。他們還提供了各種開發(fā)語言的客戶端,例如 Java(這是必須的:帜怼)痪宰、Phython、Ruby匆光,等等……

在本文中套像,筆者將主要討論 Java 客戶端,因?yàn)檫@很可能是安卓開發(fā)者最了解的開發(fā)語言终息。

編寫你自己的 publisher

讓我們看看如何編寫定制化的谷歌電子市場 publisher夺巩。分為兩步:首先,我們要配置控制臺周崭,讓客戶端能夠操作柳譬,然后探索 API。通常跟谷歌建立連接時最困難的就是配置……相關(guān)文檔可以在這里找到续镇。請注意美澳,文檔也許不是最新版的。

配置

首先摸航,如果沒有現(xiàn)成的制跟,你需要在谷歌控制臺新建一個項(xiàng)目。接下來酱虎,我們需要啟用 Google Play Android Developer API雨膨。


Once it is done, we must create a credential of type Service account key:

完成之后,我們必須創(chuàng)建一個 Service account key 類型的證書:

最后读串,填寫小表聊记,下載 JSON 格式的證書文件。你需要保存三個值:private_key_id爹土、private_keyclient_email甥雕。把 private_key 的值保存到它自己的 secret.pem 文件。

開發(fā)者控制臺搞定了……現(xiàn)在我們來看第二個控制臺吧胀茵!

連接到你的電子市場控制臺社露。你需要依次訪問 Settings > API access

接下來,你只需要連接你的項(xiàng)目琼娘。最后在 Service accounts峭弟,授權(quán)你在 JSON 文件的 client_email 處填寫的郵箱地址附鸽。

現(xiàn)在好了。一切搞定瞒瘸!

探索 API

現(xiàn)在讓我們通過 Java 客戶端訪問接口坷备。我們在 publisher 上面創(chuàng)建一個單獨(dú)的 Java 項(xiàng)目,并且添加以下依賴項(xiàng)(在 maven central 有):

compile 'com.google.apis:google-api-services-androidpublisher:
v2-rev20-1.21.0'

下一步是新建一個 AndroidPublisher情臭。首先省撑,我們通過以下信息來實(shí)例化 GoogleCredential:一個客戶端連接,一個 JSON factory俯在,一個與 private_key_id 對應(yīng)的私有關(guān)鍵 ID竟秫,一個與 client_email 對應(yīng)的賬戶 ID,ANDROIDPUBLISHER 范圍跷乐,以及與 private_key 對應(yīng)的肥败、包含私有關(guān)鍵信息的重要文件。是的愕提,所有這些都需要馒稍。

然后,我們用應(yīng)用程序包創(chuàng)建一個 AndroidPublisher 例子浅侨。

http = GoogleNetHttpTransport.newTrustedTransport();
json = JacksonFactory.getDefaultInstance();

Set<String> scopes =
      Collections.singleton(AndroidPublisherScopes.ANDROIDPUBLISHER);

GoogleCredential credential = new GoogleCredential.Builder().
                setTransport(http).
                setJsonFactory(json).
                setServiceAccountPrivateKeyId(KEY_ID).
                setServiceAccountId(SERVICE_ACCOUNT_EMAIL).
                setServiceAccountScopes(scopes).
                setServiceAccountPrivateKeyFromPemFile(secretFile).
                build();

publisher = new AndroidPublisher.Builder(http, json, credential).
                setApplicationName(PACKAGE).
                build();

AndroidPublisher 是谷歌 API 的主要入口纽谒。它有一個 edits 方法,可以讓我們修改想從控制臺獲取的數(shù)據(jù)仗颈。

要開始一個新版本佛舱,你必須用 insert 請求來開始,然后保存它的 id挨决,接下來每次調(diào)用都會使用該 id。

AndroidPublisher.Edits edits = publisher.edits();

AppEdit edit = edits.insert(PACKAGE, null).execute();
String id = edit.getId();

現(xiàn)在订歪,我們可以開始修改控制臺數(shù)據(jù)了脖祈。舉個例子,如果你想修改排名:

Listings listings = edits.listings();

Listing listing = new Listing().
                        setFullDescription(description).
                        setShortDescription(shortDescription).
                        setTitle(title);

listings.update(PACKAGE, id, "en_US", listing).execute();

You can also upload screenshots:

也可以上傳截圖:

Images images = edits.images();

FileContent content = new FileContent(PNG_MIME_TYPE, file);

images.upload(PACKAGE, id, "en_US", "phone5", content).execute();

最后一個例子刷晋,上傳一個 APK:

// APK upload
Apks apks = edits.apks();
FileContent apkContent = new FileContent(APK_MIME_TYPE, apkFile);
Apk apk = apks.upload(PACKAGE, id, apkContent).execute();
int version = apk.getVersionCode();

// Assign APK to Track
Tracks tracks = edits.tracks();
List<Integer> versions = Collections.singletonList(version)
Track track = new Track().setVersionCodes(versions);
tracks.update(PACKAGE, id, "production", track).execute();

// Update APK listing
Apklistings apklistings = edits.apklistings();
ApkListing whatsnew = new ApkListing().setRecentChanges(changes);
apklistings.update(PACKAGE, id, version, "en_US", whatsnew).execute();

筆者鼓勵你多多探索這個接口盖高。它既強(qiáng)大,又不復(fù)雜眼虱。

最后一步喻奥,你必須提交自己的版本。實(shí)際上捏悬,谷歌會記錄你的每一個更改請求撞蚕,但是只有在你提交版本之后,這些更改才會被保存过牙。筆者同時建議你在提交之前先驗(yàn)證這些更改甥厦。

edits.validate(PACKAGE, id).execute();
edits.commit(PACKAGE, id).execute();

如你所見纺铭,你在代碼開頭找回的 id 可以被當(dāng)做事務(wù) id。通過調(diào)用 insert,update/upload 你的更改以開始事務(wù)刀疙,validate 以及最終 commit舶赔。非常簡單。

結(jié)論

現(xiàn)在谦秧,安卓應(yīng)用程序也可以呼應(yīng) DevOps 活動竟纳,擁有強(qiáng)有力的持續(xù)交付了。在 Captain Train疚鲤,我們選擇編寫自己的 publisher 工具來確保自己控制每個步驟和重要步驟的字節(jié)蚁袭。一旦發(fā)布任務(wù)成功完成,我們就把它當(dāng)做一個腳本來運(yùn)行石咬。不過也有 Jenkins 插件或 Gradle 插件可以幫你完成這些工作揩悄。只是要注意了解幕后的運(yùn)行情況。畢竟你在處理生產(chǎn)鬼悠。必須小心謹(jǐn)慎删性。

這樣的工具和流程讓你只需推送 master 分支即可在生產(chǎn)環(huán)境中發(fā)布新版本。既簡單焕窝、快捷蹬挺,又可靠、節(jié)約時間它掂。

顯然巴帮,在一個應(yīng)用程序中可行的方法不一定適用于所有的團(tuán)隊(duì)、公司和應(yīng)用程序虐秋。還要依靠你的團(tuán)隊(duì)以及團(tuán)隊(duì)與市場傳播團(tuán)隊(duì)的關(guān)系榕茧。不過,在此筆者想要總結(jié)的是客给,持續(xù)交付應(yīng)該成為每個開發(fā)團(tuán)隊(duì)的目標(biāo)用押,往這個目標(biāo)邁進(jìn)的每一步都是一種勝利。

OneAPM Mobile Insight 以真實(shí)用戶體驗(yàn)為度量標(biāo)準(zhǔn)進(jìn)行 Crash 分析靶剑,監(jiān)控網(wǎng)絡(luò)請求及網(wǎng)絡(luò)錯誤蜻拨,提升用戶留存。訪問 OneAPM 官方網(wǎng)站感受更多應(yīng)用性能優(yōu)化體驗(yàn)桩引,想閱讀更多技術(shù)文章缎讼,請?jiān)L問 OneAPM 官方技術(shù)博客
本文轉(zhuǎn)自 OneAPM 官方博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末坑匠,一起剝皮案震驚了整個濱河市血崭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖功氨,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件序苏,死亡現(xiàn)場離奇詭異,居然都是意外死亡捷凄,警方通過查閱死者的電腦和手機(jī)忱详,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來跺涤,“玉大人匈睁,你說我怎么就攤上這事⊥按恚” “怎么了航唆?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長院刁。 經(jīng)常有香客問我糯钙,道長,這世上最難降的妖魔是什么退腥? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任任岸,我火速辦了婚禮,結(jié)果婚禮上狡刘,老公的妹妹穿的比我還像新娘享潜。我一直安慰自己,他們只是感情好嗅蔬,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布剑按。 她就那樣靜靜地躺著,像睡著了一般澜术。 火紅的嫁衣襯著肌膚如雪艺蝴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天瘪板,我揣著相機(jī)與錄音吴趴,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛厢拭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播供鸠,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了薄坏?” 一聲冷哼從身側(cè)響起趋厉,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤胶坠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后沈善,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體乡数,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年闻牡,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片罩润。...
    茶點(diǎn)故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖金度,靈堂內(nèi)的尸體忽然破棺而出拳球,到底是詐尸還是另有隱情,我是刑警寧澤祝峻,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站莱找,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏辞色。R本人自食惡果不足惜浮定,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望桦卒。 院中可真熱鬧,春花似錦建蹄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽旭绒。三九已至谆棱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間垃瞧,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工脉幢, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嗦锐,地道東北人嫌松。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓奕污,卻偏偏與公主長得像,于是被迫代替她去往敵國和親碳默。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評論 2 355

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理髓废,服務(wù)發(fā)現(xiàn)该抒,斷路器,智...
    卡卡羅2017閱讀 134,657評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,152評論 25 707
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫冈爹、插件欧引、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,105評論 4 62
  • 之前寫的是用jq寫的 過時了被我刪除了 現(xiàn)在的這個方法比較完善 說的再多 不如復(fù)制運(yùn)行看一下效果吧image....
    陽光之城alt閱讀 6,281評論 0 2
  • 寫在小寶8個月16天 小寶在身邊酣睡著维咸,小奶嘴咬得嘎嘎響,那可愛的睡姿讓人忍不住偷笑癌蓖。 小寶每天晚上八點(diǎn)半準(zhǔn)時開始...
    陌上花開Air閱讀 168評論 0 1