Android 應(yīng)用構(gòu)建速度提升的十個(gè)小技巧

應(yīng)用的構(gòu)建速度會(huì)直接影響開(kāi)發(fā)效率焙格,本文將帶您通過(guò)改造一個(gè) Android 應(yīng)用: “Google 追蹤圣誕老人 (Google Santa Tracker)” 來(lái)為大家提供十個(gè)小技巧,幫助提升應(yīng)用的 Gradle 構(gòu)建速度,當(dāng)我們應(yīng)用了所有的小技巧之后渴频,該演示應(yīng)用的構(gòu)建速度快了三倍以上捡絮。

首先來(lái)了解一下 “Google 追蹤圣誕老人” 應(yīng)用的工程背景: 這個(gè)應(yīng)用有約 60M 大小梗搅,它包含 9 個(gè)模塊,有 500 多個(gè) Java 文件弹砚,1,700 多個(gè) XML 文件、3,500 多張 PNG 圖片資源枢希,用到了 Mutil-dex桌吃,沒(méi)有注解處理器。

其次苞轿,在我們開(kāi)啟速度提升調(diào)優(yōu)之前茅诱,來(lái)了解本次三個(gè)性能指標(biāo)的說(shuō)明:

? ? ?> 全量構(gòu)建,也就是重新開(kāi)始編譯整個(gè)工程的 debug 版搬卒;

? ? ?>?代碼增量構(gòu)建瑟俭,指的是我們修改了工程的 Java / Kotlin 代碼;

? ? ?>?資源增量構(gòu)建契邀,指的是我們對(duì)資源文件的修改摆寄,增加減少了圖片和字符串資源等。

每個(gè)小技巧實(shí)施以后蹂安,我們會(huì)對(duì)比如上三個(gè)場(chǎng)景的構(gòu)建時(shí)間以作為我們的量化標(biāo)準(zhǔn)椭迎。請(qǐng)注意,由于工程規(guī)模大小不一田盈、開(kāi)發(fā)環(huán)境各異畜号,開(kāi)發(fā)者們?cè)趯?shí)際的操作中的結(jié)果可能會(huì)與本文的結(jié)果有所不同。

小技巧 1: 使用最新版本的 Android Gradle 插件

每次 Android Gradle 插件的更新都會(huì)修復(fù)大量的 bug 及提升性能等新特性允瞧,因此保持最新的 Android Gradle 插件版本有非常大的必要简软。

從 3.0 版本開(kāi)始,我們將通過(guò) google() 的 Maven 倉(cāng)庫(kù)分發(fā)新的 Android Gradle 插件述暂,所以需要在 repositories 處加入 google() 以獲得最新的插件更新 (現(xiàn)在的 Android Studio 新建工程的時(shí)候會(huì)默認(rèn)加入 google() 的 Maven 倉(cāng)庫(kù)指向)痹升。

這是將 Android Gradle 插件版本從 2.x 更新到 3.0.0-alpha1 之后得到的結(jié)果 (這里的演示是基于 3.0.0-alpha1 版本,隨著插件版本的更新畦韭,性能的提升會(huì)更加明顯)疼蛾,我們可以看出,全量構(gòu)建一次應(yīng)用的時(shí)間直接減少了 25%艺配,代碼改動(dòng)的增量構(gòu)建減少了將近 40%察郁,資源改動(dòng)的增量構(gòu)建也減少了 16%衍慎。

小技巧 2: 避免激活舊版的 Multidex

這個(gè)小技巧大家應(yīng)該比較熟悉——避免激活舊版的 multidex。當(dāng)您的應(yīng)用配置方法數(shù)超過(guò) 64K 的時(shí)候皮钠,您需要啟用 multidex稳捆。當(dāng)您啟用了 multidex,且工程的最低 API 級(jí)別在 21 之前時(shí)麦轰,舊版的 multidex 就會(huì)被激活乔夯,這將嚴(yán)重拖慢您的構(gòu)建速度,原因是 21 之前的 API 級(jí)別并沒(méi)有原生的支持 multidex款侵。

如果您是通過(guò) Android Studio 的運(yùn)行/調(diào)試按鈕來(lái)執(zhí)行構(gòu)建末荐,那么無(wú)需考慮這個(gè)問(wèn)題,新版本的 Android Studio 會(huì)自動(dòng)檢測(cè)連接的設(shè)備和模擬器喳坠,如果系統(tǒng)的 API 級(jí)別大于 21 則進(jìn)行原生的 multidex 支持鞠评,同時(shí)會(huì)忽略工程里對(duì)最低 API 級(jí)別?(minSdkVersion) 的設(shè)置。

習(xí)慣通過(guò)命令行窗口構(gòu)建工程的開(kāi)發(fā)者們則需要試著避免這個(gè)問(wèn)題:?配置一個(gè)新的 productFlavor壕鹉,設(shè)定工程的最低 API 級(jí)別為 21 或者以上剃幌,在命令行里調(diào)用 assembleDevelopmentDebug 即可避免這個(gè)問(wèn)題。

這一次的性能改進(jìn)結(jié)果效果也非常明顯 (灰色的線(xiàn)條是最初的結(jié)果)晾浴,在全量構(gòu)建的時(shí)候我們又降低了 5.5 秒的時(shí)間负乡,而在代碼改動(dòng)的增量構(gòu)建里時(shí)間減少了 50% 以上,資源改動(dòng)的增量構(gòu)建與之前的時(shí)間相同脊凰。

小技巧 3: 禁用 Multiple APK 構(gòu)建

在應(yīng)用需要發(fā)布和上架的時(shí)候抖棘,我們往往會(huì)使用 “Multiple APK” 構(gòu)建,它可以根據(jù) ABI 和像素密度創(chuàng)建不同版本的應(yīng)用狸涌,使包體積降低等切省。但這個(gè)在開(kāi)發(fā)階段似乎顯得有些多余,所以我們需要禁用多 APK 構(gòu)建特性以提高構(gòu)建速度帕胆。

禁用多 APK 構(gòu)建不能僅僅在 splits 里設(shè)置朝捆,因?yàn)檫@里的設(shè)置對(duì)工程里所有的構(gòu)建變體都是可見(jiàn)的。正確的禁用多 APK 構(gòu)建的方法是創(chuàng)建一個(gè)屬性來(lái)做判斷懒豹,這里我們?cè)O(shè)置了一個(gè)名為 “devBuild” 的屬性芙盘,在構(gòu)建的過(guò)程中把這個(gè)值傳給 gradle,此時(shí) gradle 會(huì)將 splits.abi.enable 和 splits.density.enable 設(shè)置為 false脸秽,它就不會(huì)生成多個(gè) APK 了儒老。

在 Android Studio 里,您可以通過(guò)偏好設(shè)置记餐,構(gòu)建驮樊、執(zhí)行和部署分類(lèi)里,選擇編譯器選項(xiàng)來(lái)為命令行加入?yún)?shù):?-PdevBuild,這樣每次在構(gòu)建的時(shí)候 Android Studio 會(huì)把這個(gè)值傳遞給 gradle 以避免生成多個(gè) APK囚衔。

如上圖所示铝穷,這是我在禁用了多 APK 之后的效果,各項(xiàng)指標(biāo)都在繼續(xù)降低佳魔。

小技巧 4: 最小化使用資源文件

當(dāng)您的應(yīng)用包含大量本地化資源或者為不同像素密度加入了特別的資源時(shí),您可能需要應(yīng)用這個(gè)小技巧來(lái)提高構(gòu)建速度——最小化開(kāi)發(fā)階段打包進(jìn)應(yīng)用的資源數(shù)量晦炊。

構(gòu)建系統(tǒng)默認(rèn)會(huì)將聲明過(guò)或者使用過(guò)的資源全部打包進(jìn) APK鞠鲜,但在開(kāi)發(fā)階段我們可能只用到了其中一套而已,針對(duì)這種情況断国,我們需要使用 resConfigs() 來(lái)指定構(gòu)建開(kāi)發(fā)版本時(shí)所需要用到的資源贤姆,如語(yǔ)言版本和屏幕像素密度。

這里我們看到了較大程度上的改觀稳衬,全量構(gòu)建的時(shí)間又降低了 6 秒霞捡,增量構(gòu)建的時(shí)間也分別降低了 20% 以上。

小技巧 5: 禁用 PNG 壓縮

與小技巧 4 一樣薄疚,這個(gè)特性本身在打包發(fā)布階段是相當(dāng)有幫助的—— PNG 壓縮碧信,但在開(kāi)發(fā)階段禁用這個(gè)功能可以提高構(gòu)建效率。默認(rèn)情況下街夭,AAPT 會(huì)壓縮工程的 PNG 資源以減小 APK 體積砰碴,根據(jù)圖片的數(shù)量和大小,這個(gè)過(guò)程所消耗的時(shí)間有長(zhǎng)有短板丽。

如果要避免使用 PNG 壓縮呈枉,我們可以在小技巧 3 里提到的,在 devBuild 屬性里加入 aaptOptions.cruncherEnabled = false 來(lái)實(shí)現(xiàn)埃碱,在構(gòu)建的過(guò)程中把這個(gè)值傳給 gradle猖辫,它就可以避免執(zhí)行 PNG 壓縮命令了。

另外一個(gè)避免壓縮 PNG 的方法是使用把 PNG 轉(zhuǎn)換成 WebP 格式的圖片砚殿,對(duì)比 PNG 格式啃憎,WebP 可以減少最多 25% 的大小,同時(shí) 2.3 以上版本的 Android Studio 直接支持 PNG 到 WebP 格式的轉(zhuǎn)換瓮具。

需要注意的是荧飞,API 級(jí)別 15 及更高可以支持不透明的 WebP 格式圖片,如果是透明格式的 WebP名党,需要 API 級(jí)別 18 以及更高叹阔。

這可以看到全量構(gòu)建又減少了 9 秒的時(shí)間,這也是因?yàn)?Google 追蹤圣誕老人應(yīng)用里有 3,500 多張 PNG 圖片传睹,這要花費(fèi)大量的時(shí)間進(jìn)行壓縮計(jì)算耳幢,所以這方面的效率提升顯得很明顯,而其他增量構(gòu)建只是維持了之前的情況。

特別提出一下關(guān)于 APK 體積的問(wèn)題——對(duì)比了啟用和禁用 PNG 壓縮之后的 APK 體積之后睛藻,我們發(fā)現(xiàn)前后的體積并沒(méi)有太大改變启上,這說(shuō)明該工程里使用的 PNG 圖片在導(dǎo)入之前已經(jīng)經(jīng)過(guò)了充分優(yōu)化,PNG 壓縮在這里實(shí)屬多此一舉店印。

小技巧 6: 使用 Apply Changes

從 Android Studio 3.5 版開(kāi)始 (3.5 版目前在 Beta 構(gòu)建渠道發(fā)布)冈在,開(kāi)發(fā)者們可以使用 Apply Changes 功能來(lái)提高構(gòu)建性能,它可以讓代碼和資源的改動(dòng)直接生效而無(wú)需重啟應(yīng)用按摘,有時(shí)候甚至無(wú)需重啟當(dāng)前的 Activity包券。與 Instant Run 的實(shí)現(xiàn)方式不一樣,Apply Changes 充分利用了 Android 8.0 以上版本操作系統(tǒng)的特性進(jìn)行運(yùn)行時(shí)檢測(cè)炫贤,從而動(dòng)態(tài)的對(duì)類(lèi)進(jìn)行重新定義溅固。因此,如果您希望使用 Apply Changes兰珍,則需要讓您的工程運(yùn)行在 Android 8.0 (API級(jí)別26) 以上的真機(jī)或者模擬器上侍郭。

小技巧 7: 避免被動(dòng)的改動(dòng)

我們通過(guò)一個(gè)很小的例子來(lái)說(shuō)明這個(gè)小技巧:?我們把工程的版本號(hào)設(shè)定為基于當(dāng)前時(shí)間的數(shù)字 (實(shí)際上大家應(yīng)該不會(huì)這么操作),這樣的結(jié)果是每次構(gòu)建的時(shí)候版本號(hào)都是新的掠河,工程的清單文件會(huì)因此發(fā)生改變亮元,最后帶來(lái)的結(jié)果就是拖慢了本次的構(gòu)建速度。

如圖所示口柳,我們發(fā)現(xiàn)增量構(gòu)建的時(shí)間甚至增加了一倍苹粟,因此盡量不要在構(gòu)建腳本里加入太多無(wú)意義的內(nèi)容。

解決這個(gè)問(wèn)題并不難跃闹,我們可以通過(guò)在構(gòu)建腳本里判斷是否有 devBuild 標(biāo)記嵌削,如果有的話(huà),我們就把版本號(hào)設(shè)置為一個(gè)固定值就可以了望艺。

這個(gè)例子里苛秕,我們故意在構(gòu)建腳本中加入里一些搗亂的代碼以展現(xiàn)其帶來(lái)的損失。同時(shí)也舉一個(gè)在使用 Crashlytics 時(shí)的實(shí)際例子找默,這個(gè)插件默認(rèn)會(huì)為每次構(gòu)建中都加入唯一 ID 作為構(gòu)建標(biāo)識(shí)艇劫,這會(huì)帶來(lái)不必要的時(shí)間損失,您可以通過(guò)在構(gòu)建腳本里加入 ext.alwaysUpdateBuildId = false 來(lái)避免這個(gè)惩激,當(dāng)然也可以選擇在開(kāi)發(fā)階段完全關(guān)閉 Crashlytics店煞。

小技巧 8: 不使用動(dòng)態(tài)版本標(biāo)識(shí)

Gradle 提供了一個(gè)非常方便的依賴(lài)庫(kù)版本號(hào)管理功能,方便開(kāi)發(fā)者們通過(guò)使用一個(gè)加號(hào) “+” 標(biāo)識(shí)希望使用這個(gè)依賴(lài)庫(kù)的最新版本风钻。但是使用動(dòng)態(tài)版本有幾個(gè)風(fēng)險(xiǎn)顷蟀,從性能角度來(lái)說(shuō),Gradle 會(huì)每隔 24 小時(shí)去檢查一次依賴(lài)庫(kù)的更新骡技,如果您的依賴(lài)庫(kù)很多鸣个,而且都使用了動(dòng)態(tài)獲取最新版本的這個(gè)設(shè)定羞反,那會(huì)對(duì)構(gòu)建時(shí)候的性能產(chǎn)生一定的影響。

即使您不是特別在意這些性能損耗囤萤,但是它仍然是有風(fēng)險(xiǎn)的——依賴(lài)庫(kù)的版本更新會(huì)讓您的構(gòu)建充滿(mǎn)不確定性昼窗,可能兩周之后您就在構(gòu)建一個(gè)完全不一樣的工程了,因?yàn)橐蕾?lài)庫(kù)代碼的更新對(duì)開(kāi)發(fā)者們是不可見(jiàn)的涛舍。

小技巧 9: Gradle 內(nèi)存分配調(diào)優(yōu)

默認(rèn)的構(gòu)建環(huán)境里澄惊,我們會(huì)給 Gradle 分配 1.5G 的內(nèi)存,但這個(gè)并非適用于所有的項(xiàng)目富雅,您需要通過(guò)對(duì)這個(gè)數(shù)字對(duì)調(diào)優(yōu)來(lái)得到適合您工程的最佳 Gradle 內(nèi)存分配缤削。

與此同時(shí),從 Android Gradle 插件 2.1 版本之后吹榴,dex 已經(jīng)默認(rèn)在進(jìn)程里了,所以如果您之前設(shè)定過(guò) javaMaxHeapSize 值滚婉,可以選擇刪掉它了图筹。

小技巧 10: 開(kāi)啟 Gradle 構(gòu)建緩存

Gradle 新推出的緩存機(jī)制效果非常出色,我們建議大家嘗試開(kāi)啟让腹,最新的 Gradle 支持了 Kotlin 項(xiàng)目使用構(gòu)建緩存远剩,構(gòu)建速度可以降低很多。Gradle 的構(gòu)建緩存默認(rèn)是不開(kāi)啟的骇窍,您可以通過(guò)在命令行里加入 --build-cache 參數(shù)或者在工程根目錄的 gradle.properties 里加入 org.gradle.caching=true 為所有人啟用構(gòu)建緩存瓜晤。您可以在這個(gè)文檔里了解更多關(guān)于 Gradle 構(gòu)建緩存的內(nèi)容。

總結(jié)

在實(shí)踐了所有的速度提升小技巧之后腹纳,得到的整體的改善結(jié)果痢掠,全量構(gòu)建的速度比之前快了三倍以上,而代碼改動(dòng)的增量構(gòu)建則快了 12 倍以上嘲恍,我們?cè)?GitHub 上創(chuàng)建了一個(gè)代碼倉(cāng)庫(kù)足画,大家可以下載并實(shí)踐一下我們今天所提到的構(gòu)建速度提升的技巧。更多關(guān)于如何提高應(yīng)用構(gòu)建速度的內(nèi)容佃牛,請(qǐng)關(guān)注我們的官方文檔淹辞。

點(diǎn)擊這里提交產(chǎn)品反饋建議

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市俘侠,隨后出現(xiàn)的幾起案子象缀,更是在濱河造成了極大的恐慌,老刑警劉巖爷速,帶你破解...
    沈念sama閱讀 221,273評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件咧栗,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡狞甚,警方通過(guò)查閱死者的電腦和手機(jī)裂允,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人禁谦,你說(shuō)我怎么就攤上這事胁黑。” “怎么了州泊?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,709評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵丧蘸,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我遥皂,道長(zhǎng)力喷,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,520評(píng)論 1 296
  • 正文 為了忘掉前任演训,我火速辦了婚禮弟孟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘样悟。我一直安慰自己拂募,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布窟她。 她就那樣靜靜地躺著陈症,像睡著了一般。 火紅的嫁衣襯著肌膚如雪震糖。 梳的紋絲不亂的頭發(fā)上录肯,一...
    開(kāi)封第一講書(shū)人閱讀 52,158評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音吊说,去河邊找鬼论咏。 笑死,一個(gè)胖子當(dāng)著我的面吹牛颁井,可吹牛的內(nèi)容都是我干的潘靖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,755評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼蚤蔓,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼卦溢!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起秀又,我...
    開(kāi)封第一講書(shū)人閱讀 39,660評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤单寂,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后吐辙,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體宣决,經(jīng)...
    沈念sama閱讀 46,203評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評(píng)論 3 340
  • 正文 我和宋清朗相戀三年昏苏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了尊沸。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片威沫。...
    茶點(diǎn)故事閱讀 40,427評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖洼专,靈堂內(nèi)的尸體忽然破棺而出棒掠,到底是詐尸還是另有隱情,我是刑警寧澤屁商,帶...
    沈念sama閱讀 36,122評(píng)論 5 349
  • 正文 年R本政府宣布烟很,位于F島的核電站,受9級(jí)特大地震影響蜡镶,放射性物質(zhì)發(fā)生泄漏雾袱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評(píng)論 3 333
  • 文/蒙蒙 一官还、第九天 我趴在偏房一處隱蔽的房頂上張望芹橡。 院中可真熱鬧,春花似錦望伦、人聲如沸僻族。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,272評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至蝌数,卻和暖如春愕掏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背顶伞。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,393評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工饵撑, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人唆貌。 一個(gè)月前我還...
    沈念sama閱讀 48,808評(píng)論 3 376
  • 正文 我出身青樓滑潘,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親锨咙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子语卤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評(píng)論 2 359

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