本文为稀土技术社区首发签约文章,30天内制止转载,30天后未获授权制止转载,侵权必究!
1、写在前面
提高编译速度最快的是晋级电脑装备,其次是接入Gradle Enterprice企业版,这两者简单粗犷,带来的效果也十分显着,但是这两者的本钱却不必定是所有人都能承受的,特别是目前咱们都在搞降本增效,所以想要靠外在力气来提高编译速度更是难上加难,遂,有了本文,经过Gradle装备最佳实践的方法来协助咱们低本钱的提高编译速度。
钱不是问题,问题是没钱。
2、为什么要做编译优化
功能优化的三驾马车是发动、包巨细和内存,这三个指标都跟用户的体会休戚相关,所以编译优化就变成了重要不紧迫
的事情,但编译优化也能带来诸多优点,主要有两点:
- 提高开发功率:开发者能够更快地编译和运转代码,这意味着对代码的改变能够更快的得到反应,然后加速开发周期,提高个人和整个团队的生产力;
- 提高开发体会:削减了等待时间,提高个人和整个团队的幸福感和满意度;
影响摸鱼?干完不是能够摸的更酣畅吗…
3、影响编译速度的因素
主要有以下几个方面:
- 硬件功能:CPU、RAM等;
- 构建装备:缓存、增量编译等;
- 项目:项目的巨细和复杂度,代码量、模块化、依靠管理等;
- 其他:网络速度,下载慢或许找不到等;
4、编译优化准则
所以,根据上面影响编译速度的因素来看,编译优化准则也能够推导为两个方面:
- 复用:提高复用率,不只是代码的复用,也是编译产物的复用,不只重视初次编译速度,也要重视二次编译速度;
- 更少:削减参与编译的文件,越少则处理越快,不只是代码文件,还有资源文件;
5、最佳实践
ok,上面铺垫了这么多,下面给咱们介绍一些有用的构建装备。
5.1、晋级版别
5.1.1、晋级Gradle
Gradle
作为一个构建东西,提高构建功能能够说是基础操作,基本每个大版别都会带来各式各样的功能提高,比方Gradle 6.6今后对装备阶段的提高,7.0今后对Kotlin编译的提高,8.0今后对增量编译的进一步提高等等,这些都是构建东西之外无法做到的,所以,假如你的Gradle还不是最新版别,有条件的话必定要试试。
尽管晋级Gradle有必定的适配本钱,但是假如不升,长此以往,技术负债只会越来越多。
Keeping up with Gradle version upgrades is low risk because the Gradle team ensures backwards compatibility between minor versions of Gradle.
官方还说是低危险,
5.1.2、晋级Java
Gradle是运转在Java虚拟机上的,即JVM,Java功能的提高也会有利于Gradle。
5.1.3、晋级Plugin
同Gradle,一般也都是跟随着Gradle升一波。
5.2、敞开并行编译
Gradle默许一次只履行一个Task,即串行,那咱们就能够经过装备让Gradle并行来履行Task,然后提高构建功率,缩短构建时间。
在gradle.properties
文件中添加:
org.gradle.parallel=true
5.3、敞开守护进程
敞开守护进程之后,Gradle不只能够更好的缓存构建信息,并且运转在后台,不必每次构建都去初始化然后再发动JVM了。
在gradle.properties
文件中添加:
org.gradle.daemon=true
以上两个装备,在GradleX项目中测验,增量编译速度提高60%以上,实际以自己项目为准。
5.4、启用装备缓存
装备缓存是Gradle 6.6今后供给的能力。
当没有构建装备发生变化的时分,比方构建脚本,Gradle会直接跳过装备阶段,然后带来功能的提高。
构建装备主要是scripts和properties,一般事务开发也不会动这个,所以仍是十分有用的。
org.gradle.unsafe.configuration-cache=true
5.5、启用构建缓存
同一个Task的输入不变的情况下,Gradle直接去检索缓存中检索输出,就不必再次履行该Task了。
org.gradle.caching=true
5.6、启用增量编译
Gradle 4.10及以上默许敞开,假如是4.10以下的版别,能够加上如下代码手动敞开。
build.gradle:
tasks.withType(JavaCompile).configureEach {
options.incremental = true
}
关于Task的增量编译,请看这篇:【Gradle-7】Gradle构建中心之Task攻略 –
5.7、添加JVM堆巨细
默许是512m的堆巨细,多数情况下并不够用,能够经过jvmargs
来调整内存堆巨细。
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
2048m=2g,也能够写成
org.gradle.jvmargs=-Xmx2g -Dfile.encoding=UTF-8
这个巨细能够根据自己电脑装备来调整。
5.8、运用 JVM 并行废物收回器
经过装备Gradle所用的最佳JVM废物收回器,能够提高构建功能。-XX:+UseParallelGC
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 -XX:+UseParallelGC
5.9、添加Android Studio运转内存
上面说到添加Gradle的内存堆巨细,AS的运转内存空间相同也能够调整。
调整AS内存的装备文件在AS > Contents > bin > studio.vmoptions
文件中
打开文件:
-Xms256m
-Xmx1280m
-XX:ReservedCodeCacheSize=512m
-XX:+UseG1GC
-XX:SoftRefLRUPolicyMSPerMB=50
-XX:CICompilerCount=2
-XX:+HeapDumpOnOutOfMemoryError
.....
这儿主要有两个参数需求重视:
- -Xms256m:初始堆内存巨细;
- -Xmx1280m:最大堆内存巨细;
能够修改为:
-Xms256m
-Xmx2048m
然后保存并重启AS收效即可。
Android Studio的运转内存占比能够在AS底部的东西栏上右键,把Memory Indicator
勾选上,然后在右下角就能够显示出来了。
5.10、优化依靠解析
5.10.1、删除无用的依靠
能够经过Gradle Lint Plugin来识别未运用的依靠项,然后删除,然后削减构建时间。
5.10.2、优化存储库次序
Gradle在解析依靠时,默许依照装备声明的库房地址次序去查找,即自上而下,所以为了削减查找依靠项花费的时间,一般会依照项目中运用的依靠项归属的库房来摆放库房地址次序。
Android开发用的比较多的是google(),其次是mavenCentral(),所以这俩应该是在前面的,其他的看自己项目依靠情况摆放。
repositories {
google()
mavenCentral()
// others
}
5.10.3、优化依靠的下载速度
因为有些库房的地址是在国外的,导致很多同学就常常遇到下载依靠很慢的情况,所以咱们能够运用一些国内的镜像来提高下载速度。
repositories {
// 阿里云库房
maven { url 'https://maven.aliyun.com/repository/public/' }
google()
mavenCentral()
}
阿里云镜像整理:juejin.cn/post/690747…
5.10.4、优化依靠版别
防止运用动态版别
(2.+)和快照版别
(2-SNAPSHOT),这样能够防止Gradle在构建的时分去检索新版别,默许是24
小时检查一次。
比方微信的SDK,为了让咱们及时更新就运用了动态版别:
api 'com.tencent.mm.opensdk:wechat-sdk-android:+'
看下SDK的介绍,直接运用详细的版别:
api 'com.tencent.mm.opensdk:wechat-sdk-android:6.8.23'
关于动态版别和快照版别的检索时效也能够经过以下装备来设置:
configurations.all {
// 动态版别缓存时效
resolutionStrategy.cacheDynamicVersionsFor(10, "minutes")
// 快照版别缓存时效
resolutionStrategy.cacheChangingModulesFor(4, "hours")
}
5.11、防止编译不必要的资源
防止编译和打包不测试的资源(例如,其他言语本地化和屏幕密度资源)。能够仅为“dev”变种的版别指定一个言语资源和屏幕密度,如下:
android {
productFlavors {
dev {
...
resourceConfigurations "en", "xxhdpi"
}
}
}
5.12、按需编译
道理同上,运用assembleDebug
或许assembleRelease
,来替代assemble
。
同理,还有debugImplementation
、abiFilters
。
以及按需依靠插件:
if(debug){
apply xxx
}
5.13、禁用不需求的Task
还有Task也是同理,比方跳过Lint
和Test
相关的task, 以加速编译。
//跳过Lint和Test相关的task, 以加速编译
if (isDebug()) {
gradle.taskGraph.whenReady {
tasks.each { task ->
if (task.name.contains("Test") || task.name.contains("Lint")) {
task.enabled = false
}
}
}
}
5.14、将图片转换为WebP格局
WebP
是一种既能够供给有损紧缩(像 JPEG 相同)也能够供给透明度(像 PNG 相同)的图片文件格局。与 JPEG或PNG比较,WebP格局能够供给更好的紧缩效果。
减小图片文件巨细能够加速构建速度(无需在构建时进行紧缩),尤其是当运用运用大量图片资源时。
Android Studio中:
选中图片 > 右键 > Convert to WebP
5.15、停用PNG处理
即便不将PNG图片转换为WebP格局,依然能够在每次构建运用时停用主动图片紧缩,以加速构建速度。
android {
buildTypes {
release {
crunchPngs false
}
}
}
5.16、运用非传递R类
运用非传递 R 类可为具有多个模块的运用构建更快的 build。这样做有助于保证每个模块的 R 类仅包含对其本身资源的引证,而不会从其依靠项中提取引证,然后协助防止资源重复。这样能够获得更快的 build,以及防止编译的相应优势。在Android Gradle 插件 8.0.0 及更高版别中的默许敞开。
android.nonTransitiveRClass=true
从 Android Studio Bumblebee 开始,新项目的非传递 R 类默许处于敞开状态。 对于运用早期版别的 Android Studio 创建的项目,能够在 Refactor > Migrate to Non-transitive R Classes
,将项目更新为运用非传递 R 类。
5.17、停用Jetifier标志
因为大多数项目都直接运用 AndroidX 库,因此能够移除Jetifier
标志,以便获得更好的构建功能。
android.enableJetifier=false
Jetifier
是把support包转成AndroidX的东西,现在基本上都现已适配AndroidX了,能够关掉,然后提高构建功能。
假如你是敞开的,即android.enableJetifier=true
,能够运用Build Analyzer
东西来查看是否会有正告,即是否能够移除。
5.18、运用KSP替代kapt
kapt
是Kotlin注解处理东西,kapt的运转速度显着慢于Kotlin Symbol Processor (KSP)。官方:速度提高多达2倍。
5.18.1、启用KSP
project:
plugins {
id("com.google.devtools.ksp") version "1.8.10-1.0.9" apply false
}
app:
plugins {
id("com.google.devtools.ksp")
}
5.18.2、运用KSP
dependencies {
// kapt
kapt("androidx.room:room-compiler:2.5.0")
// ksp
ksp("androidx.room:room-compiler:2.5.0")
}
就这么简单,然后移除kapt相关的装备即可。前提是运用的库现已适配了KSP,干流的基本现已适配。
5.18.3、K2
在kotlin 1.9.20
中K2现已处于beta版别了,会有进一步的功能提高。
尝鲜能够在gradle.properties中加上以下装备:
kotlin.experimental.tryK2=true
kapt.use.k2=true
更多可查看:kotlin-k2-compiler。
5.19、去掉动态装备
每次编译之后会发生不同成果的装备。
5.19.1、动态的FileName
比方每次打包会把apk的姓名加上当前构建时间,这样不只会发生大量的文件,并且每次都要更新,影响编译速度。
applicationVariants.all { variant ->
variant.outputs.all { output ->
outputFileName = "${variant.name}-${buildTime()}.apk"
}
}
static def buildTime() {
return new Date().format("MMdd_HHmm", TimeZone.default)
}
5.19.2、动态的VersionName
defaultConfig {
versionCode $buildTime().toInteger()
versionName '1.0.$buildTime()'
}
static def buildTime() {
return new Date().format("MMdd_HHmm", TimeZone.default).toInteger()
}
道理同上,动态的versionCode
和versionName
也是不推荐的。
5.20、其他
5.20.1、敞开离线模式
老版别能够在Settings>Build>Gradle
中把offline work
勾选上,或许在编译脚本里加上--offline
。
5.20.2、优化DexOptions
老版别装备:
android {
dexOptions {
// 运用增量模式构建
incremental true
// 最大堆内存
javaMaxHeapSize "4g"
// 是否支持大工程模式
jumboMode = true
// 预编译
preDexLibraries = true
// 线程数
threadCount = 8
// 进程数
maxProcessCount 4
}
}
5.20.3、模块化
一般项目中运用了模块化的这种架构设计,都会做源码依靠和AAR依靠的切换,来提高构建速度,主要是削减了参与编译的代码,再加上缓存,所以提高效果显着。这个后边独自写一篇介绍下。
5.20.4、构建剖析
运用构建剖析来处理项目中的构建耗时点,以及不合理装备,参阅:【Gradle-10】不可忽视的构建剖析。
6、总结
本文先是介绍了为什么要做编译优化,然后剖析了影响编译速度的因素有哪些,从最少、复用的构建准则入手,详细的为咱们介绍了一些低本钱且有用的最佳实践攻略。假如你还没有优化过,能够实操起来了~
假如本文对你有一点点协助,请不要吝啬你的点赞和重视~