Open itgoyo opened 5 years ago
为了避免被Diss,先声明了,本文不算原创,只是对几篇Gradle编译提速的文章进行了: 搬运、整理、细化和补漏,文尾已列出相关的参考文献!先上个图舒服下:
(PS:这是直接新建的项目通过各种折腾后编译的时间,笔者公司的项目折腾完耗时5s左右, 但是因为兼容要改的东西多,升级gradle等操作并没弄,不过也是效果明显,真的可以试试~)
大部分的Android开发仔吐槽的最多的基本都是等Gradle编译。
编译可以说是日常操作最频繁的,在调UI,调试改Bug时候达到一个峰值,每改点东西, 就build一下。可以说是相当可怕,我们来粗略的算一笔账:
假设编译一次要3分钟,一天编译40次 每天花费:2小时等待编译 一周花费:14小时等待编译 一个月花费:60小时等待编译 => 2.5天
假设编译一次要3分钟,一天编译40次
每个月花2.5天是在等待Gradle编译,多呆哦,所以,让Gradle编译提速,显得格外重要, 本节就从方方面面说下减少这个等待的时间吧。
大部分的Gradle编译卡和慢,都是因为电脑配置的原因,个人感觉关键基本配置如下:
CPU:i5系列就够了 内存:重要!至少要8G,有条件建议上16G 硬盘:重要!必须是SSD固态硬盘,穷一点的上128G,稍微宽裕点上256
其他比如显卡啊啥的没什么太大影响,配置肯定是越高越好,在自己的经济承受范围以内即可。
电脑配置差不多了,接下来就要调整下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明显打开流畅多了。
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就可以了,分配更多的内存并不会使构建加快多少!
除了配置给gradle分配的内存外,还可以通过添加下述配置使得构建加快:
#开启守护线程 org.gradle.daemon=true #开启并行编译任务 org.gradle.parallel=true #开启缓存 android.enableBuildCache=true 复制代码
另外,你还可以在下述目录中创建一个gradle.properties文件,全局生效,就不用每个项目都另外配置了, 当然你喜欢还是可以在项目中创建这个文件。
就是使用阿国内阿里云的依赖下载地址替换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' } ... } } 复制代码
如果你的项目比较稳定,没有什么新的依赖(第三方库引用),可以使用这种方法来提升编译速度。 依次点击菜单栏「Setting」->「Build」-> 「Gradle」,找到如图的「Offline work」勾选,点击OK即可。
也可以不配置,在命令行编译的时候加上--offline,比如:
--offline
gradlew build --offline 复制代码
在引用依赖库的时候,尽量避免使用+这种动态版本号,而尽量使用静态编码编码版本号, 如果用动态版本号,每次编译的时候Gradle会去检查是否有更新,比如:
# 动态版本号 com.android.tools.build:gradle:3.2.+ # 静态版本号 com.android.tools.build:gradle:3.2.1 复制代码
你可以通过下述两种方式,查看编译的时候都执行了哪些Task,以及他们的耗时。
方法一:通过gradlew --profile
编译命令后加上--profile,比如 gradlew build --profile,会输出打包过程的profile report。
gradlew build --profile
接着按照给出的路径找到对应的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阶段并不需要,我们可以下述三种方式来禁用:
gradlew build -x lint -x lintVitalRelease 复制代码
项目级别的build.gradle中buildScript添加下述代码:
gradle.startParameter.excludedTaskNames.add('lint') gradle.startParameter.excludedTaskNames.add('lintVitalRelease') 复制代码
在模块级别的build.gradle中的
apply plugin: 'com.android.application' 复制代码
前加上下述代码:
tasks.whenTaskAdded { task -> if (task.name.contains("lint") || task.name.contains("lintVitalRelease")) { task.enabled = false } } 复制代码
Gradle在编译时会执行大量Task,生成很多中间文件,会导致磁盘IO拥堵,造成编译变慢, 可以减少本地库依赖,多使用aar进行依赖。
如果你不需要兼容低版本的设备的话,可以把minSdkVersion改为21以上(Android 5.0),使用ART,在Build时只做class to dex, 而不做mergeing dex,同样会节省一点的时间。
注:Gradle版本需大于3.4,示例如下:
compile 'com.android.support:appcompat-v7:28.0.0' # 改为: implementation 'com.android.support:appcompat-v7:28.0.0' 复制代码
同样的替换还有:
有效减少图片文件大小,不必执行构建时压缩,从而加快构建速度,如果你的APP用到大量图片资源的话,效果明显。
如果不想把图片替换成WebP,可在每次构建应用时停用自动图像压缩的方式加快构建速度。模块级别build.gradle添加下述代码:
android { ... aaptOptions { cruncherEnabled false } } 复制代码
直接gradlew build和执行gradlew assemble 会同时编译生成Debug和Release的包,在调试阶段其实 我们可以使用:
gradlew build
gradlew assemble
gradlew assembleDebug 复制代码
来只编译Debug版本的包,除此之外还可以用另一个命令编译完直接安装到设备上:
gradlew installDebug 复制代码
同理对应Release的命令为:
gradlew assembleRelease gradlew installRelease 复制代码
行吧,关于Gradle编译提速大概就这些,有补充的欢迎在评论区留言,谢谢~
参考文献:
官方文档:优化您的构建速度
Decreasing build times by decreasing gradle memory requirements!
Gradle加速
第 8 点很不错
为了避免被Diss,先声明了,本文不算原创,只是对几篇Gradle编译提速的文章进行了: 搬运、整理、细化和补漏,文尾已列出相关的参考文献!先上个图舒服下:
(PS:这是直接新建的项目通过各种折腾后编译的时间,笔者公司的项目折腾完耗时5s左右, 但是因为兼容要改的东西多,升级gradle等操作并没弄,不过也是效果明显,真的可以试试~)
大部分的Android开发仔吐槽的最多的基本都是等Gradle编译。
编译可以说是日常操作最频繁的,在调UI,调试改Bug时候达到一个峰值,每改点东西, 就build一下。可以说是相当可怕,我们来粗略的算一笔账:
每个月花2.5天是在等待Gradle编译,多呆哦,所以,让Gradle编译提速,显得格外重要, 本节就从方方面面说下减少这个等待的时间吧。
1.升级下你的电脑配置
大部分的Gradle编译卡和慢,都是因为电脑配置的原因,个人感觉关键基本配置如下:
其他比如显卡啊啥的没什么太大影响,配置肯定是越高越好,在自己的经济承受范围以内即可。
2.调整AS的内存分配
电脑配置差不多了,接下来就要调整下AS的可使用内存,打开AS在右下角可以看到使用内存和分配内存,如图所示:
如果你的AS里没有这个图的话,可以依次点击菜单栏的:「File」->「Settings」->「Appearance % Behavior」-> 「Appearance」-> 找到如图所示的「Show memory indicator」勾选,然后点击OK,就可以在状态栏看到内存分配信息了。
接着我们来修改AS的内存分配,来到AS的安装目录下,进入bin目录,找到:
用文本编辑类软件打开对应文件,内容如下:
接着我们修改下前三项,改成更大的值:
修改完后保存,然后回到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的内存比dex的内存多1g,dex进程内存设置在开发module的 build.gradle里面控制。添加如下内容:
除此之外,dexOptions中还可以添加下述配置:
配置完dex,接着要配置gradle,打开「gradle.properties」修改org.gradle.jvmargs 的大小,按照公式,多1g,所以这里配置成2g:
除此之外设置下JVM最大允许分配的非堆内存,以及堆内存移除时输出堆的内存快照。
接着可以再Terminal中中键入gradlew clean build来看看构建的速度是否加快了。 一般dex设置为1-2G,gradle设置为2-4G就可以了,分配更多的内存并不会使构建加快多少!
4.其他gradle.properties配置
除了配置给gradle分配的内存外,还可以通过添加下述配置使得构建加快:
另外,你还可以在下述目录中创建一个gradle.properties文件,全局生效,就不用每个项目都另外配置了, 当然你喜欢还是可以在项目中创建这个文件。
5.配置依赖包下载地址
就是使用阿国内阿里云的依赖下载地址替换Google依赖包下载地址,打开Project级别的build.gradle文件,添加阿里云的地址:
6.离线编译
如果你的项目比较稳定,没有什么新的依赖(第三方库引用),可以使用这种方法来提升编译速度。 依次点击菜单栏「Setting」->「Build」-> 「Gradle」,找到如图的「Offline work」勾选,点击OK即可。
也可以不配置,在命令行编译的时候加上
--offline
,比如:7.使用静态依赖项版本
在引用依赖库的时候,尽量避免使用+这种动态版本号,而尽量使用静态编码编码版本号, 如果用动态版本号,每次编译的时候Gradle会去检查是否有更新,比如:
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文件中添加相关代码:
接着命令键入:gradlew build --scan,编译完会问你是否Push到gradle.com,键入: yes即可。
如果不想每次都键入yes,在build.gradle中添加下述代码:
接着点击打开链接,会让你输入一个接收报告的邮箱:
接着会受到一个邮件,点开就能看到本次编译的相关信息了,比如这里看到占较多编译时间的Task是lint:
行吧,从上面的两个例子我们可以明显的看到lint耗时不少,而Lint在Debug阶段并不需要,我们可以下述三种方式来禁用:
项目级别的build.gradle中buildScript添加下述代码:
在模块级别的build.gradle中的
前加上下述代码:
9.一些其他的小点
① 减少本地库依赖
Gradle在编译时会执行大量Task,生成很多中间文件,会导致磁盘IO拥堵,造成编译变慢, 可以减少本地库依赖,多使用aar进行依赖。
② 修改minSdkVersion>=21
如果你不需要兼容低版本的设备的话,可以把minSdkVersion改为21以上(Android 5.0),使用ART,在Build时只做class to dex, 而不做mergeing dex,同样会节省一点的时间。
③ 使用implementation替代compile
注:Gradle版本需大于3.4,示例如下:
同样的替换还有:
④ 将图像转换成 WebP
有效减少图片文件大小,不必执行构建时压缩,从而加快构建速度,如果你的APP用到大量图片资源的话,效果明显。
⑤ 停用 PNG 处理
如果不想把图片替换成WebP,可在每次构建应用时停用自动图像压缩的方式加快构建速度。模块级别build.gradle添加下述代码:
⑥ 按需编译而不是无脑build
直接
gradlew build
和执行gradlew assemble
会同时编译生成Debug和Release的包,在调试阶段其实 我们可以使用:来只编译Debug版本的包,除此之外还可以用另一个命令编译完直接安装到设备上:
同理对应Release的命令为:
行吧,关于Gradle编译提速大概就这些,有补充的欢迎在评论区留言,谢谢~
参考文献:
官方文档:优化您的构建速度
Decreasing build times by decreasing gradle memory requirements!
Gradle加速