本文为稀土技术社区首发签约文章,30天内制止转载,30天后未获授权制止转载,侵权必究!

1、写在前面

提高编译速度最快的是晋级电脑装备,其次是接入Gradle Enterprice企业版,这两者简单粗犷,带来的效果也十分显着,但是这两者的本钱却不必定是所有人都能承受的,特别是目前咱们都在搞降本增效,所以想要靠外在力气来提高编译速度更是难上加难,遂,有了本文,经过Gradle装备最佳实践的方法来协助咱们低本钱的提高编译速度。

【Gradle-14】编译优化之Gradle最佳装备实践

钱不是问题,问题是没钱。

2、为什么要做编译优化

功能优化的三驾马车是发动、包巨细和内存,这三个指标都跟用户的体会休戚相关,所以编译优化就变成了重要不紧迫的事情,但编译优化也能带来诸多优点,主要有两点:

  1. 提高开发功率:开发者能够更快地编译和运转代码,这意味着对代码的改变能够更快的得到反应,然后加速开发周期,提高个人和整个团队的生产力;
  2. 提高开发体会:削减了等待时间,提高个人和整个团队的幸福感和满意度;

影响摸鱼?干完不是能够摸的更酣畅吗…

3、影响编译速度的因素

主要有以下几个方面:

  • 硬件功能:CPU、RAM等;
  • 构建装备:缓存、增量编译等;
  • 项目:项目的巨细和复杂度,代码量、模块化、依靠管理等;
  • 其他:网络速度,下载慢或许找不到等;

4、编译优化准则

所以,根据上面影响编译速度的因素来看,编译优化准则也能够推导为两个方面:

  1. 复用:提高复用率,不只是代码的复用,也是编译产物的复用,不只重视初次编译速度,也要重视二次编译速度;
  2. 更少:削减参与编译的文件,越少则处理越快,不只是代码文件,还有资源文件;

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文件中

【Gradle-14】编译优化之Gradle最佳装备实践

打开文件:

-Xms256m
-Xmx1280m
-XX:ReservedCodeCacheSize=512m
-XX:+UseG1GC
-XX:SoftRefLRUPolicyMSPerMB=50
-XX:CICompilerCount=2
-XX:+HeapDumpOnOutOfMemoryError
.....

这儿主要有两个参数需求重视:

  • -Xms256m:初始堆内存巨细;
  • -Xmx1280m:最大堆内存巨细;

能够修改为:

-Xms256m
-Xmx2048m

然后保存并重启AS收效即可。

【Gradle-14】编译优化之Gradle最佳装备实践

Android Studio的运转内存占比能够在AS底部的东西栏上右键,把Memory Indicator勾选上,然后在右下角就能够显示出来了。

【Gradle-14】编译优化之Gradle最佳装备实践

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

同理,还有debugImplementationabiFilters

以及按需依靠插件:

if(debug){
  	apply xxx
}

5.13、禁用不需求的Task

还有Task也是同理,比方跳过LintTest相关的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()
}

道理同上,动态的versionCodeversionName也是不推荐的。

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】不可忽视的构建剖析

【Gradle-14】编译优化之Gradle最佳装备实践

6、总结

本文先是介绍了为什么要做编译优化,然后剖析了影响编译速度的因素有哪些,从最少、复用的构建准则入手,详细的为咱们介绍了一些低本钱且有用的最佳实践攻略。假如你还没有优化过,能够实操起来了~

假如本文对你有一点点协助,请不要吝啬你的点赞和重视~

7、GitHub

github.com/yechaoa/Gra…

8、相关文档