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

Build is Fast in 3.2, But You Can Make it Faster

Build is Fast in 3.2, But You Can Make it Faster

Overview of performance improvements in Android Studio 3.2, as well as generate build performance tips and tricks both for small and large scale projects.

Avatar for Artem Chubaryan

Artem Chubaryan

October 11, 2018

Other Decks in Programming

Transcript

  1. Gradle 4.10.2 • Incremental Java Compilation • Heap usage dropped

    from 350MB to 10MB • Kotlin DSL 1.0 RC (because devs refuse to learn Groovy) • Periodic cache cleanup (or 5.0)
  2. R8/D8 • D8 is more stable than ever • Integrated

    Desugaring is on • R8 is available Art by Kevin Kwok
  3. Updating the flags android.enableD8 = false android.enableD8.desugaring = true org.gradle.configureondemand

    = true android.enableR8 = true kotlin.incremental.usePreciseJavaTracking = true kapt.use.worker.api = true org.gradle.parallel = true org.gradle.caching = true gradle.properties
  4. Build structure 1. Initialization & Configuration 2. Build task execution

    3. Shrinking & obfuscation (optional) ~ 2-60 sec ~0.5-6 min
  5. Gradle Build Cache • Reuse build outputs of any previous

    execution • Reuse build outputs even if run with clean task • Uniquely identifies outputs of tasks by inputs
  6. Gradle Remote Build Cache • Shared among different machines •

    Reuse build results among CI agents/jobs and individual developers • Set up for free on CI with Docker image • Or remotely with Gradle Enterprise
  7. Setting up Remote Cache //settings.gradle //Check if build is ran

    locally or on CI def ciServer = gradle.properties.gradleUserHomeDir?.parentFile?.name == 'build' buildCache { local { enabled = !ciServer //CI shouldn't use local cache } remote(HttpBuildCache) { enabled = true url = 'http://nexus.mobitv.com/cache/' push = ciServer //push to cache from CI only credentials { username = 'admin' password = 'admin' } } }
  8. Why cache doesn’t get hit?! • CRLF vs LF •

    UTF-8 encoding • Annotations • You used timestamps • 3rd party library used timestamps • Variables in BuildConfig.java • Crashlytics’ unique ids I will write a blogposts on these, I promise!
  9. Repositories • Reorder and clean repos • Get rid of

    Maven Central • Use local Nexus Repository Manager
  10. //this is very bad repositories { maven { url 'https://objectbox.net/beta-repo/'

    } maven { url 'https://maven.fabric.io/public' } maven { url 'https://maven.localytics.com/public' } google() mavenCentral() jcenter() }
  11. Tame your dependencies! module:core +-- com.squareup.moshi:moshi:1.7.0 \-- com.squareup.okio:okio:1.15.0 +-- module:rest

    \-- com.squareup.okhttp3:okhttp:3.11.0 \-- com.squareup.okio:okio:1.14.0 Both versions are downloaded!
  12. Tame your dependencies! module:core +-- com.squareup.moshi:moshi:1.7.0 \-- com.squareup.okio:okio:1.15.0 +-- module:rest

    \-- com.squareup.okhttp3:okhttp:3.11.0 \-- com.squareup.okio:okio:1.14.0 \-- com.squareup.okio:okio:1.15.0 Both versions are downloaded!
  13. Minimizing amount of code • Remove unused libraries • Remove

    unused code and modules (use Lint and Proguard reports) • Disable unnecessary modules in settings.gradle //settings.gradle //Include easter egg module only when building EE app. if (startParameter?.taskNames?.count {name -> name.contains('easterEgg')} > 0) { include ':easterEgg' }
  14. Forcing single-variant environment 1. Generate build variant dynamically 2. Set

    current flavor in Gradle script ext.currentFlavor = 'cspire' 3. Add extra build parameter to enable all variants gradlew build –PBUILD_ALL 4. Pain 5. ??? 6. PROFIT
  15. Multi-module projects • Use implementation instead of api • Modules

    should compile in parallel, not in sequence • Split modules into more submodules! • java lib compile faster than android lib • No Kotlin code in module? Don’t apply Kotlin plugin! • Build Scans and Build Cache FTW!
  16. Cleaning up unit tests • Make tests flavor-independent • Keep

    tests only for one product variant android { def isUnitTestBuild = … //read from build arguments //product flavors: 'mobileonly', 'tv', 'firetv' variantFilter { variant -> def names = variant.flavors*.name if (isUnitTestBuild && (names.contains('mobileonly') || names.contains('tv'))) { setIgnore(true) } } }
  17. Cleaning up unit tests • Use Build Scans to find

    slowest tests • Mockito is slow, Powermock is slower • Be careful with multithreading and delays
  18. Android Studio 3.3 is coming • Lazy task configuration •

    Single-variant project sync • R8 is (probably not) enabled by default • Gradle 5.x