Optimizing Android Build Time with Module AAR Strategy in Ctrip's Train Ticket App
This article describes how Ctrip's Train Ticket Android project reduced its clean Gradle build time by more than half using a module‑AAR approach, custom dependency substitution, Maven publishing, and automated tooling, while detailing the challenges, code changes, and performance results.
Background: The Train Ticket Android project, built with Gradle, suffered from long clean‑build times (up to 10 minutes 39 seconds), severely impacting developer productivity. The goal was to cut the clean‑build duration to less than 50 % of the original.
Solution Overview: Adopt a module AAR strategy—publish each of the 20 sub‑modules as AAR artifacts to a remote Maven repository and replace source dependencies with these AARs during the build. This reduces the amount of code compiled in each build and shortens overall packaging time.
Key Implementation Steps:
Define custom dependency‑resolution rules using Gradle’s resolutionStrategy.dependencySubstitution based on a JSON configuration ( app_bundles.json ) that marks a module as aar or lib . // pseudo‑code, normally extracted to a plugin gradle.ext.appBundles.each { bundleName, bundleInfo -> if (bundleInfo.buildType == 'aar') { gradle.ext.subsitituteMap[":$bundleName"] = "$specialGroupID:$bundleName:${bundleInfo.versionName}" } } configurations.all { conf -> resolutionStrategy.dependencySubstitution { gradle.ext.subsitituteMap.each { substitute project(it.key) with module(it.value) } } }
Publish AARs with the maven-publish plugin and generate a custom POM to control transitive dependencies. apply plugin: 'maven-publish' publishing { // ... other settings ... pom { packaging = "aar" withXml { pomGenerate(it) } } } def ascribeDependencies(String confName) { /* collect ExternalModuleDependency */ } def pomGenerate(XmlProvider xp) { /* add nodes */ }
Provide a helper compileBundle method to add either project or AAR dependencies based on the JSON configuration. def compileBundle(Project project, String depName = null) { def projectName = depName ?: project.name def handler = project.configurations.implementation if (projectName != project.name) { def p = project.rootProject.findProject(projectName) if (p) handler.dependencies.add(project.dependencies.create(p)) } else if (gradle.ext.moduleTransitives) { gradle.ext.moduleTransitives[projectName]?.each { def p = project.rootProject.findProject(it.depName) if (p) handler.dependencies.add(project.dependencies.create(p)) } } }
Maintain a versionPath.json file (generated by the MCD platform) that records the published AAR version for each module, allowing the build script to fetch the correct artifact when no explicit version is supplied.
Introduce an IDE plugin that visualizes the JSON configuration, lets developers drag‑and‑drop modules between src and aar modes, and writes the changes back to local.properties for CI/CD consumption.
Additional Challenges Addressed:
Resource name collisions between AARs were detected with the open‑source CheckResourceConflict plugin, producing an HTML report that lists duplicate resources and their locations.
Publishing AARs without ProGuard/R8 obfuscation to avoid runtime class‑not‑found errors.
Handling dependencySubstitution limitations (only groupId:artifactId:version allowed) and avoiding UnsupportedNotationException by ensuring no classifier is added.
Preventing StackOverflowError caused by dynamic Groovy methods in substituted projects by skipping their Gradle scripts when a substitution is active.
Results:
First clean build: source code average 8 min 47 s, AAR average 4 min 24 s (≈50 % reduction).
Second clean build: source code average 5 min 50 s, AAR average 3 min 15 s (≈44 % reduction).
Overall release package time reduced by roughly half when all modules are built as AARs.
Conclusion: The module‑AAR strategy, combined with custom Gradle scripts, CI/CD automation, and IDE tooling, significantly speeds up Android compilation for large multi‑module projects, while also exposing new complexities in dependency management and resource handling that must be carefully managed.
Ctrip Technology
Official Ctrip Technology account, sharing and discussing growth.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.