Android Gradle 构建优化
背景
本地构建的时候一次需要比较长的时间,存在优化空间。可以使用 --profile
参数来分析构建过程中各个任务的耗时情况,比如 ./gradlew assembleDebug --profile
本文基于的硬件条件:
- MacBook Pro 2017
- 8G + 256G
现状
./gradlew assembleDebug --profile
增量编译:
首次编译(无缓存):
开发时构建优化
开发时的 Gradle 构建优化比较有意义,构建测试包、正式包的时候并不需要那么关注构建时间。可以将开发时的构建与提测构建分离,新建一个本地开发用的 productFlavor - local
,本地开发时只构建 local
包,在本地开发构建过程中禁用掉不必要的任务(比如 lint, multidex, optimization 等),减少构建时间。
优化开发构建中的 Dalvik 可执行文件分包
https://developer.android.com/studio/build/multidex#multidexkeepproguard
新建一个 local 的 productFlavor,设置 minSdkVersion 为 21,这样就会启用 pre-dexing 构建功能(仅适用于 Android 5.0+),能够加快打包速度,改动如下:
禁用构建时对 /res/drawable
目录下图片的优化
Android 构建工具默认会对 drawable 下的图片进行优化,比如图片压缩转换,校验等,这个过程是比较耗时的,尤其是当图片比较多的时候。改动如下:
dexOptions 配置优化
android.dexOptions 的配置优化
一些比较老的文章还会推荐 dexOptions.incremental
,这是没必要的,在 Gradle 2.1.0-rc1 (2016-04-22) 之后,incremental 增量构建已经默认启用了,不再需要显式声明。 此外,dexOptions.jumboMode
参数也是可选的,在启用 instant-run 时这个参数会默认启用
使用 Gradle 依赖缓存
Gradle 在构建时都会去拉依赖,顺序是:本地缓存 -> 远程依赖。如果使用了动态版本,那么每次 Gradle 都会拉最新的依赖,在依赖多的情况下是非常耗时的,从下面这张图可以看出(挖财宝):
从上图中可以看出,光是拉依赖就用了 3 分钟,这都还没到编译阶段,难怪打个包要六七八分钟。。。
在 Gradle 中,最好固定依赖的版本号,这样就不会每次编译都重新拉依赖,但是在目前快速迭代的背景下,一般都是锁死第一位,第二位和第三位版本号自动更新,也没法锁死依赖,只能把之前 resolutionStrategy 改一下,使用 Gradle 默认的动态版本号缓存策略(Gradle 的动态版本也会有缓存滴),改动如下:
改动之后的效果分析如下,拉依赖的时间从 3min 变成了 20s 左右,效果明显。
但是这种情况下,如果 snapshot 版本的依赖更新了,可能不会及时自动更新到本地(因为缓存),不过 Gradle 支持 --refresh-dependencies
参数,使用 ./gradlew assembleLocalDebug --refresh-dependencies
会全量刷新依赖。
gradle.properties 中的一系列优化参数(可选)
org.gradle.daemon = true
Gradle 是基于 JVM 的构建系统,JVM 的启动和初始化需要时间,开启 Gradle Daemon 守护进程可以节省这些时间
org.gradle.configureondemand = true
一次 Gradle 编译大概由这几部分组成:初始化、加载 setting.gradle(|| setting.gradle.kts)、加载各个模块的 build.gradle(|| build.gradle.kts)、执行一系列任务。从上图中可以看到,Configuring Projects 也是花了 5s 左右的时间,使用 org.gradle.configureondemand=true
可以加速这一过程。
org.gradle.parallel = true
启用 Gradle 并行编译,加速编译过程
org.gradle.jvmargs = -Xmx2560M
设置 Gradle 编译时使用的最大内存,大一点比较好,但是我的小本本内存只有 8G,有心无力。。。 使用大内存时 Android 编译过程中的 dexing 就不会单独开进程进行,能节省构建时间。
android.enableBuildCache = true
启用 Android 编译构建缓存,此举能极大提升构建效率,推荐! 但是我司因为统跳编译插件不支持编译缓存,因此只能禁用。
综上所述
综上所述,挖财宝中启用的开发时构建优化措施有:
- 设置 minSdkVersion 为 21
- 对
/res/drawable
目录下图片的优化 - dexOptions 配置优化
- jumboMode = true
- javaMaxHeapSize = "2g"
- preDexLibraries = true
- threadCount = 8
- gradle.properties 配置优化
- org.gradle.daemon = true
- org.gradle.configureondemand = true
- org.gradle.parallel = true
- org.gradle.jvmargs = -Xmx2560M,大内存的话可以再大一点
- android.enableBuildCache = true 用不了。
优化后使用 ./gradlew assembleLocalDebug
生成开发包,或者使用 ./gradlew installLocalDebug
直接安装。 提测时使用 offcialDebug
或者 qqDebug
均可。打生产包时使用 offcialRelease
或者 qqRelease
。
优化之后的效果如下图所示,增量编译一般可以控制在 2min 以内
增量编译:
首次编译(无缓存):
题外话
- 其实,提升 Gradle 构建速度的最有效途径不在上面,很简单,换个 Mac Pro 来编译就好了
- 上文中提到的几个 gradle.properties 中的配置,如果只想本地使用,就不要写在 gradle.properties 中,可以写在 local.properties 或 ~/.gradle/gradle.properties 中
- 如果条件允许的话,使用最新的 Gradle 版本吧,新版的 Gradle 构建速度绝对比旧版本的快(目前是 Gradle 5.0)
- 移除不必要的三方依赖
- 按需编译,部分 task 在开发的时候是不需要执行的,比如 lint,直接禁用掉即可,可以使用
--profile
参数进行分析,分析报告在build/reports/profile/
目录下 - 优化永无止境
参考资料
Personal
- 微信公众号:yongf666
- 掘金:https://juejin.im/user/57b8751a2e958a005fa2fc45
- 个人网站:https://www.54yongf.com/
- 微博:http://weibo.com/2902237231
- 知乎:http://www.zhihu.com/people/wang-yong-8-33
- 邮箱:ScottWang1996@gmail.com
- StackOverflow:http://stackoverflow.com/users/5304207