為了避免被Diss,先宣告瞭,本文不算原創,只是對幾篇Gradle編譯提速的文章進行了: 搬運、整理、細化和補漏,文尾已列出相關的參考文獻!先上個圖舒服下:
(PS:這是直接新建的專案通過各種折騰後編譯的時間,筆者公司的專案折騰完耗時5s左右, 但是因為相容要改的東西多,升級gradle等操作並沒弄,不過也是效果明顯,真的可以試試~)
大部分的Android開發仔吐槽的最多的基本都是等Gradle編譯。
編譯可以說是日常操作最頻繁的,在調UI,除錯改Bug時候達到一個峰值,每改點東西, 就build一下。可以說是相當可怕,我們來粗略的算一筆賬:
假設編譯一次要3分鐘,一天編譯40次
- 每天花費:2小時等待編譯
- 一週花費:14小時等待編譯
- 一個月花費:60小時等待編譯 => 2.5天
每個月花2.5天是在等待Gradle編譯,多呆哦,所以,讓Gradle編譯提速,顯得格外重要, 本節就從方方面面說下減少這個等待的時間吧。
1.升級下你的電腦配置
大部分的Gradle編譯卡和慢,都是因為電腦配置的原因,個人感覺關鍵基本配置如下:
- CPU:i5系列就夠了
- 記憶體:重要!至少要8G,有條件建議上16G
- 硬碟:重要!必須是SSD固態硬碟,窮一點的上128G,稍微寬裕點上256
其他比如顯示卡啊啥的沒什麼太大影響,配置肯定是越高越好,在自己的經濟承受範圍以內即可。
2.調整AS的記憶體分配
電腦配置差不多了,接下來就要調整下AS的可使用記憶體,開啟AS在右下角可以看到使用記憶體和分配記憶體,如圖所示:
如果你的AS裡沒有這個圖的話,可以依次點選選單欄的:「File」->「Settings」->「Appearance % Behavior」-> 「Appearance」-> 找到如圖所示的「Show memory indicator」勾選,然後點選OK,就可以在狀態列看到記憶體分配資訊了。
接著我們來修改AS的記憶體分配,來到AS的安裝目錄下,進入bin目錄,找到:
用文字編輯類軟體開啟對應檔案,內容如下:
-Xms256m
-Xmx1280m
-XX:ReservedCodeCacheSize=240m
-XX:+UseConcMarkSweepGC
-XX:SoftRefLRUPolicyMSPerMB=50
-Dsun.io.useCanonCaches=false
-Djava.net.preferIPv4Stack=true
-Djna.nosys=true
-Djna.boot.library.path=
-da
複製程式碼
接著我們修改下前三項,改成更大的值:
-Xms512m //JVM啟動的起始堆記憶體,堆記憶體是分配給物件的記憶體
-Xmx2560m //Java虛擬機器啟動時的引數,用於限制最大堆記憶體
-XX:ReservedCodeCacheSize=480m //JIT java compiler在compile的時候的最大程式碼快取
-XX:+UseConcMarkSweepGC
-XX:SoftRefLRUPolicyMSPerMB=50
-Dsun.io.useCanonCaches=false
-Djava.net.preferIPv4Stack=true
-Djna.nosys=true
-Djna.boot.library.path=
複製程式碼
修改完後儲存,然後回到AS中,依次點選選單欄:「File」->「Ivalidate Caches/Restart...」,點選後出現如圖對話方塊,點選「Ivalidate Caches/Restart...」。
然後等待AS重啟即可。然後右下角可以看到可用記憶體已經發生了改變,AS明顯開啟流暢多了。
3.增加Gradle的堆大小並啟用dex-in-process
Dex-in-process允許你dex和gradle構建在同一個程式進行,以此加快增量構建和乾淨構建的速度。 要使用dex-in-process非常簡單:確保 grale 程式有足夠的記憶體分配給 dex 步驟來完成整個操作。 建議的公式:
Gradle memory >= Dex memory + 1Gb !
複製程式碼
就是分配給gradle的記憶體比dex的記憶體多1g,dex程式記憶體設定在開發module的 build.gradle裡面控制。新增如下內容:
除此之外,dexOptions中還可以新增下述配置:
//使用增量模式構建
incremental true
//是否支援大工程模式
jumboMode = true
//預編譯
preDexLibraries = true
//執行緒數
threadCount = 8
複製程式碼
配置完dex,接著要配置gradle,開啟「gradle.properties」修改org.gradle.jvmargs 的大小,按照公式,多1g,所以這裡配置成2g:
org.gradle.jvmargs=-Xmx2g
複製程式碼
除此之外設定下JVM最大允許分配的非堆記憶體,以及堆記憶體移除時輸出堆的記憶體快照。
org.gradle.jvmargs=-Xmx2g -XX:MaxPermSize=0.5g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
複製程式碼
接著可以再Terminal中中鍵入gradlew clean build來看看構建的速度是否加快了。 一般dex設定為1-2G,gradle設定為2-4G就可以了,分配更多的記憶體並不會使構建加快多少!
4.其他gradle.properties配置
除了配置給gradle分配的記憶體外,還可以通過新增下述配置使得構建加快:
#開啟守護執行緒
org.gradle.daemon=true
#開啟並行編譯任務
org.gradle.parallel=true
#開啟快取
android.enableBuildCache=true
複製程式碼
另外,你還可以在下述目錄中建立一個gradle.properties檔案,全域性生效,就不用每個專案都另外配置了, 當然你喜歡還是可以在專案中建立這個檔案。
5.配置依賴包下載地址
就是使用阿國內阿里雲的依賴下載地址替換Google依賴包下載地址,開啟Project級別的build.gradle檔案,新增阿里雲的地址:
repositories {
maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter' }
...
}
allprojects {
repositories {
maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter' }
...
}
}
複製程式碼
6.離線編譯
如果你的專案比較穩定,沒有什麼新的依賴(第三方庫引用),可以使用這種方法來提升編譯速度。 依次點選選單欄「Setting」->「Build」-> 「Gradle」,找到如圖的「Offline work」勾選,點選OK即可。
也可以不配置,在命令列編譯的時候加上**--offline
**,比如:
gradlew build --offline
複製程式碼
7.使用靜態依賴項版本
在引用依賴庫的時候,儘量避免使用+這種動態版本號,而儘量使用靜態編碼編碼版本號, 如果用動態版本號,每次編譯的時候Gradle會去檢查是否有更新,比如:
# 動態版本號
com.android.tools.build:gradle:3.2.+
# 靜態版本號
com.android.tools.build:gradle:3.2.1
複製程式碼
8.禁用耗時但在Debug時不需要的Task
你可以通過下述兩種方式,檢視編譯的時候都執行了哪些Task,以及他們的耗時。
方法一:通過gradlew --profile
編譯命令後加上--profile,比如 gradlew build --profile
,會輸出打包過程的profile report。
接著按照給出的路徑找到對應的html檔案,用瀏覽器開啟,點選「Task Execution」
然後就可以看到所有執行的Task和所需的耗時。除此之外,還可以
方法二:使用build scan(構建審視)
Gradle 官方推出的一個視覺化診斷工具,官網地址:gradle.com/build-scans…,不同的Gradle版本對應的 build-scan-plugin的版本也不同,可以在官網檢視對應的版本號:Gradle Enterprise version compatibility, 比如我的4.6對應最低版本的build scan工具的版本號為:1.8。接著在專案級別的build.gradle檔案中新增相關程式碼:
buildscript {
repositories {
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath "com.gradle:build-scan-plugin:1.8"
}
}
apply plugin: "com.gradle.build-scan"
複製程式碼
接著命令鍵入:gradlew build --scan,編譯完會問你是否Push到gradle.com,鍵入: yes即可。
如果不想每次都鍵入yes,在build.gradle中新增下述程式碼:
buildScan {
licenseAgreementUrl = 'https://gradle.com/terms-of-service'
licenseAgree = 'yes'
}
複製程式碼
接著點選開啟連結,會讓你輸入一個接收報告的郵箱:
接著會受到一個郵件,點開就能看到本次編譯的相關資訊了,比如這裡看到佔較多編譯時間的Task是lint:
行吧,從上面的兩個例子我們可以明顯的看到lint耗時不少,而Lint在Debug階段並不需要,我們可以下述三種方式來禁用:
- 1.通過Grale編譯引數禁用
gradlew build -x lint -x lintVitalRelease
複製程式碼
- 2.Gradle指令碼中動態新增編譯引數
專案級別的build.gradle中buildScript新增下述程式碼:
gradle.startParameter.excludedTaskNames.add('lint')
gradle.startParameter.excludedTaskNames.add('lintVitalRelease')
複製程式碼
- 3.永久禁用lint
在模組級別的build.gradle中的
apply plugin: 'com.android.application'
複製程式碼
前加上下述程式碼:
tasks.whenTaskAdded { task ->
if (task.name.contains("lint") || task.name.contains("lintVitalRelease")) {
task.enabled = false
}
}
複製程式碼
9.一些其他的小點
① 減少本地庫依賴
Gradle在編譯時會執行大量Task,生成很多中間檔案,會導致磁碟IO擁堵,造成編譯變慢, 可以減少本地庫依賴,多使用aar進行依賴。
② 修改minSdkVersion>=21
如果你不需要相容低版本的裝置的話,可以把minSdkVersion改為21以上(Android 5.0),使用ART,在Build時只做class to dex, 而不做mergeing dex,同樣會節省一點的時間。
③ 使用implementation替代compile
注:Gradle版本需大於3.4,示例如下:
compile 'com.android.support:appcompat-v7:28.0.0'
# 改為:
implementation 'com.android.support:appcompat-v7:28.0.0'
複製程式碼
同樣的替換還有:
- testCompile -> testImplementation
- androidTestCompile -> androidTestImplementation
- provided -> compileOnly
④ 將影像轉換成 WebP
有效減少圖片檔案大小,不必執行構建時壓縮,從而加快構建速度,如果你的APP用到大量圖片資源的話,效果明顯。
⑤ 停用 PNG 處理
如果不想把圖片替換成WebP,可在每次構建應用時停用自動影像壓縮的方式加快構建速度。模組級別build.gradle新增下述程式碼:
android {
...
aaptOptions {
cruncherEnabled false
}
}
複製程式碼
⑥ 按需編譯而不是無腦build
直接**gradlew build
和執行gradlew assemble
** 會同時編譯生成Debug和Release的包,在除錯階段其實
我們可以使用:
gradlew assembleDebug
複製程式碼
來只編譯Debug版本的包,除此之外還可以用另一個命令編譯完直接安裝到裝置上:
gradlew installDebug
複製程式碼
同理對應Release的命令為:
gradlew assembleRelease
gradlew installRelease
複製程式碼
行吧,關於Gradle編譯提速大概就這些,有補充的歡迎在評論區留言,謝謝~
參考文獻:
- 官方文件:優化您的構建速度
- Decreasing build times by decreasing gradle memory requirements!
- Gradle加速
- Gradle 提速:每天為你省下一杯喝咖啡的時間
Join in
歡迎大家加入開發交流群一起討論學習,可以新增下述的機器人小號 RobotPig,傳送『選單』
輸入對應的提示,加入對應的開發群(Android或Python),或者在公眾號『摳腚男孩』中傳送加群~
半自動拉人,會有延時,請諒解~