Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Speeding up Android Gradle Builds

Speeding up Android Gradle Builds

This is the slide deck that we presented at I/O '17.

James Lau

May 18, 2017
Tweet

Other Decks in Technology

Transcript

  1. • Use latest versions of Android Gradle plugin, Gradle and

    Android SDK build tools • Lots of bug fixes and general improvements • New features that improve performance buildscript { repositories { jcenter() + maven { url 'https://maven.google.com' } } dependencies { - classpath 'com.android.tools.build:gradle:2.2.0' + classpath 'com.android.tools.build:gradle:3.0.0-alpha1' } ... }
  2. 2.2.0 3.0.0-alpha1 Full build Incremental build Java change Incremental build

    resource change Time (s) -15s (-25%) -10s (-38%) -2.5s (-16%)
  3. • Legacy multidex == Multidex + minSdkVersion < 21 •

    Legacy multidex slows down build significantly. • Android Studio 2.3+ will automatically avoid this when running from IDE when possible. productFlavors { development { minSdkVersion 21 ... } }
  4. Full build Incremental Java change Legacy multidex Native multidex Incremental

    resource change -5.5s (-12%) Same Full build Incremental build Java change Incremental build resource change Time (s) Baseline (2.2.0) -8s (-53%)
  5. splits { abi { enable true ... } density {

    enable true ... } } • The splits{} block creates multiple smaller APKs that target specific device configurations for release. • Not needed during development.
  6. android { if (project.hasProperty('devBuild')) { splits.abi.enable = false splits.density.enable =

    false } } ---------------------------------------------------------------- $./gradlew santa-tracker:assembleDevelopmentDebug -PdevBuild
  7. Multi-APK vs Single-APK Full build Incremental Java change Incremental resource

    change Time (s) Full build Incremental build Java change Incremental build resource change Time (s) Multi-APK Single APK Baseline (2.2.0) -4.8s (-12%) -3s (-26%) -0.5s (-6%)
  8. Full build Incremental build Java change Incremental build resource change

    Time (s) All resources “en” and “xxhdpi” only Baseline (2.2.0) -6s (-17%) -2s (-21%) -1.5s (-24%)
  9. android { if (project.hasProperty('devBuild') { splits.abi.enable = false splits.density.enable =

    false aaptOptions.cruncherEnabled = false } } ---------------------------------------------------------------- $./gradlew santa-tracker:assembleDevelopmentDebug -PdevBuild
  10. ~same Full build Incremental build Java change Incremental build resource

    change Time (s) PNG crunching No PNG crunching Baseline (2.2.0) -9s (-33%) same same
  11. Time (s) Full build Incremental build Java change Incremental build

    resource change Regular Run Instant Run Baseline (2.2.0) +7s +37% -3s -42% -3s -54%
  12. Incremental build Java change Incremental build resource change Time (s)

    +3s +130% +3.6s +90% No manifest change With manifest change
  13. Time (s) Full build Incremental build Java change Incremental build

    resource change Instant Run Instant Run w/ Gradle Cache Baseline (2.2.0) -7s -25% +0.5s +12% Same
  14. Full build Incremental build Java change Incremental build resource change

    3X faster 12X faster 3X faster 59s 19s 24s 2s 15s 4.5s
  15. 1. Use latest Android Gradle plugin 2. Avoid legacy multidex

    3. Disable multi-APK 4. Include minimal resources 5. Disable png crunching 6. Use Instant Run 7. Avoid inadvertent changes 8. Don’t use dynamic versions 9. Watch the memory 10. Enable Gradle caching
  16. • Notion of Abi or Application Binary Interface • Non-Abi

    change has no impact on consumers • Abi change triggers consumer modules recompilation
  17. It’s all wrong! • No distinction between module composition and

    module implementation detail • Used to compile and run • All consumer of a module consumes all their transitive dependencies
  18. • compile • api implementation android { dependencies { compile

    project(':libX) compile project(‘:libY') implementation project(':libX') api project(':libY') } }
  19. api • Equivalent of old compile • Imported modules’ public

    APIs become your API • Easy but dangerous
  20. implementation • Imported modules not re-exported. • Consumers of your

    module do not see the public APIs of “implementation” imported modules.
  21. • Gradle can build modules in parallel • Workaround for

    lack of incremental tasks • Multiple modules -> multiple tasks -> parallel execution • Some parallelism within a task is provided but limited
  22. not • A full build that takes more than a

    couple of minutes • Incremental build that’s not much faster than full build • Almost no up-to-date task in incremental scenario
  23. • Many things can go wrong : ◦ 3rd-party plugin

    ◦ Incorrect code organization ◦ Build.gradle customization gone wild ◦ Incorrect settings (memory) • You need to spend some time understanding Gradle and your build.
  24. • Write in Java • Put in buildSrc/ • Profile

    it • Don’t use doLast(), write a custom task with inputs and outputs that is cacheable.
  25. Gradle provides tools to help understanding where the time is

    being spent : ◦ --dry-run ◦ --info ◦ --profile ◦ Gradle profiler
  26. Some tasks are running while they should be up-to-date :

    > ./gradlew assembleDebug --info Executing task ':app:processDebugManifest' (up-to-date check took 0.004 secs) due to: Input property 'mainManifest' file /app/src/main/AndroidManifest.xml has changed.
  27. • Simple tool that will output a .html page with

    each task’s execution timing. > ./gradlew clean assembleDebug --profile • Find the .html page in build/reports/profile/
  28. Add a profiler output > gradle-profiler --profile yourkit --project-dir ./

    clean santa-tracker:mergeDevelopmentDebugResources
  29. Optimize your build speed https://developer.android.com/studio/build/optimize-your-build.html Migration Guide to Android Gradle

    plugin 3.0 https://d.android.com/studio/preview/features/new-android-plugin-migration.html Santa Tracker Project fork https://github.com/jmslau/santa-tracker-android Gradle profiler https://github.com/gradle/gradle-profiler More questions? Visit us at the Android/Play Sandbox!