如果你也为多模块项目中缓慢的Gradle构建而烦恼,你并不孤单。最近,我们接受了一个挑战,为一个拥有超过100个Kotlin Multiplatform模块的客户项目显著减少构建时间,并在各个平台上实现了超过50%的速度提升。在这篇文章中,我们将介绍我们采取的步骤。我们希望这对面临类似挑战的开发者有所帮助。
对构建进行基准测试
在开始优化之前,了解基准很重要。收集所有团队成员的构建时间,确保禁用Gradle构建缓存。在任何Gradle任务命令中使用--no-build-cache
选项来禁用构建缓存运行。不出所料,在我们的案例中,基于Intel的Mac机器比Apple芯片的机器慢得多,而且我们没有使用Windows机器的人。这些信息对后续比较和改进评估至关重要。
我们意识到,下面的一些优化可能更适用于遗留项目或技术债务较多的项目。
分析工具
Gradle构建扫描
利用Gradle Build Scan的功能深入了解构建细节。在我看来,它不仅是一个诊断工具,更是一个学习工具。
在我们的案例中,我们发现了Kotlin Multiplatform设置中ios link
任务缓慢的原因。通过比较不同CI机器上的构建扫描,帮助我们确定了CI上使用的最快机器配置。启用并行构建并通过构建扫描报告分析结果,进一步验证了我们的改进。
Android Studio构建分析器
Android Studio提供了一个内置分析器工具。它检查构建性能并对潜在问题提供警告。
禁用Jetifier
使用这个工具,我们注意到由于过时的Picasso库未使用AndroidX
库而仍在使用android.enableJetifier=true
。这可能也影响了构建速度。解决这个问题包括更新Picasso
和从gradle.properties
中删除jetifier
标志。
MultiDex
通过构建分析器,我们还发现在一些模块中不必要地使用了multiDexEnabled
以及一些旧的Gradle配置。当minSdkVersion
为21时,MultiDex
是不必要的。
依赖可见性
我们观察到大量模块通过api
依赖依赖于其他模块。使用api
依赖的问题是,当实现细节改变时,Gradle会重新编译它们。这是因为它们出现在compile
类路径中。这在多模块设置中可能会导致重编译的连锁反应,影响构建时间。
为了缓解这个问题,我们将大多数依赖转移到使用implementation
,只为那些作为XCFramework
一部分导出的依赖保留api。
启用Gradle并行执行
在多子项目设置中,Gradle可以从并行执行中获得巨大收益。随着从api
到implementation的转变,启用并行执行进一步缩短了构建时间。
谨慎使用外部Gradle插件
一些Gradle插件可能是导致构建变慢的罪魁祸首。我们的项目中就有几个这样的Gradle插件。它们在每次同步时都会执行,每个任务都会运行,并遍历项目中的所有模块。
在集成之前仔细检查第三方插件,特别是在多模块设置中。避免使用subproject
或allprojects
块进行不必要的全局应用;只在需要的地方应用插件。
不必要的KMP目标
在管理Kotlin Multiplatform (KMP)项目时,评估添加的KMP目标的必要性至关重要。根据我们的经验,我们发现无意中添加项目不需要的目标会带来效率低下的问题。
例如,我们从旧的测试模块中继承了一些为某些KMP模块添加了JVM
目标的模块。随着时间推移,引入了更多模块,而JVM目标在没有任何实际用途的情况下仍然存在。这导致在构建阶段执行不必要的JVM相关构建和测试任务。
为了解决这个问题,我们建议检查你的KMP设置,并删除任何不contribu为项目功能的目标。这不仅简化了构建过程,而且减少了不必要的开销,特别是在像我们这样的大型多模块项目中。
只构建必需的XCFramework
在带有iOS组件的Kotlin Multiplatform (KMP)项目中,iOS构建任务可能是导致构建时间延长的重要因素。通常,KMP项目脚本文件包括使用iosX64()
、iosArm64()
和iosSimulatorArm64()
目标的多个iOS架构配置,或使用启用了iosArm64
和iosX64
的简写ios()
。
然而,优化这个设置很重要,特别是考虑到为不必要的架构构建会消耗大量时间和资源。例如,即使你的本地开发机器具有ARM
架构,构建X64
框架也会不必要地增加构建时间,其他架构也是如此。
一般来说,如果在一个架构上运行正常,那么很可能在其他架构上也能正常工作。所以如果你至少在本地只构建一个架构,那是可以的。一种方法是在你的gradle.properties
文件中引入一个布尔标志,创建自定义逻辑来启用特定的iOS目标。
你所在的团队中是否有人不想或不需要在本地构建Kotlin代码?我们构建了KMMBridge,这是一个帮助简化KMP中iOS开发流程的工具。
小心使用自定义Gradle任务
虽然创建自定义Gradle任务似乎是处理常见需求的便捷方式,但在多模块设置中必须谨慎行事。根据我们的经验,一些自定义任务对构建时间产生了意想不到的影响。
例如,我们有负责将资源复制到另一个文件夹的自定义任务,但它们在所有模块中运行,导致构建过程中明显的减速。为了解决这个问题,我们重新考虑了我们的方法,选择了一个不同的策略来实现所需的结果,而不影响构建效率。
关键的启示是要确保自定义任务配置适当,以避免在模块或任务之间不必要的重复。
保持构建工具更新
始终保持Android Studio、Android Gradle Plugin和Gradle本身的最新版本。每个迭代都带来改进,可能会提高构建速度。
AGP 8.+
升级到Android Gradle Plugin 8.0.0以获得优化构建的默认行为(即非传递R类),特别是对于具有多个模块的应用程序。
配置缓存
较新的构建工具对配置缓存有更好的支持。这似乎是一个非常有前途的功能,在某些情况下可以大大提高构建速度。
虽然配置缓存是加快构建的一个有前途的功能,但要确保与所有工具的兼容性。截至Kotlin 1.9.10,Kotlin Multiplatform插件仍然缺乏完全支持,限制了其效果。
Kotlin 1.9.20预计将完全支持配置缓存。我们对此非常期待。
其他考虑因素
- 确保启用Gradle Build Cache。
- 多模块设置中的Gradle文件中的代码量可能会很大。使用Gradle约定插件简化Gradle脚本,以最小化重复配置。
通过遵循这些步骤,无论项目规模或复杂性如何,你都可以提升Gradle构建的速度。祝编码愉快!