Making the Most of Your Gradle Builds

40
Making the Most of Your Gradle Builds Egor Andreevici Software Developer @ 1&1 @EgorAnd

Transcript of Making the Most of Your Gradle Builds

Making the Most of Your Gradle Builds

Egor AndreeviciSoftware Developer @ 1&1@EgorAnd

Gradle Is Evolving!

● Gradle 3.0 released○ 75% faster Gradle Daemon, enabled by default

● Android Gradle plugin 2.3.0 released○ Build cache: faster clean builds

● Gradle Script Kotlin support

In This Session

● Optimizing your Gradle build

● Becoming more productive

Optimize Your Gradle Build!

Compiling!

“Improving the performance of Gradle builds”

https://guides.gradle.org/performance/

Quick Improvements: Update Your Gradle

● Always try to use the latest Gradle version

● Latest at the moment○ Gradle: 3.4.1

○ Android Gradle plugin: 2.3.1

Quick Improvements: The Daemon

● Long-lived background process

● Enabled by default since Gradle 3.0○ Gradle 2: enable with org.gradle.daemon=true

● Disable on CI environments

● Disable with org.gradle.daemon=false in

gradle.properties (or --no-daemon)

● Stop with --stop

Quick Improvements: Parallel Execution

● Build independent subprojects in parallel

● Effect depends on project structure

● Enable with org.gradle.parallel=true

● Use with caution! Can lead to unexpected results

Profile!

./gradlew --profile asD

asD = assembleDebug

Profile Report

Profiling: Exclude Execution Step

./gradlew --profile --dry-run asD

asD = assembleDebug

Build Scans

Configuring Build Scans

buildscript { repositories { maven { url "https://plugins.gradle.org/m2/" } } dependencies { classpath "com.gradle:build-scan-plugin:1.6" }}

apply plugin: 'com.gradle.build-scan'

buildScan { licenseAgreementUrl = 'https://gradle.com/terms-of-service' licenseAgree = 'yes'}

<project-dir>/build.gradle

Creating a Build Scan

./gradlew assembleDebug -Dscan

Analyzing the Build Scan

Tips & Tricks

Use Plugins Wisely

● Every plugin adds to the build configuration time

● Remove those you don’t need!

Conditional Plugin Importing

if (project.hasProperty('dexCountEnabled')) { apply plugin: 'com.getkeepsafe.dexcount'}

./gradlew asD -PdexCountEnabled

Remove Unused Dependencies

● Affect dependency resolution time

● Bonus: decrease the dex method count!

Decrease Repository Count

Do not

allprojects {

repositories {

maven { url "..." }

jcenter()

mavenCentral()

maven { url "..." }

}

}

Do

allprojects {

repositories {

jcenter()

}

}

Exclude Build Variants

productFlavors {

qa { ... }

live { ... }

}

variantFilter { variant ->

def buildType = variant.buildType.name

def flavor = variant.flavors[0].name

if('release'.equals(buildType) && 'qa'.equals(flavor)) {

variant.ignore = true

}

}

Clean Up Your Gradle Files!

Refactor Your Dependencies

dependencies.gradle

ext.versions = [

supportLibrary: '25.3.1'

]

ext.supportDependencies = [

appcompatv7 : "com.android.support:appcompat-v7:$versions.supportLibrary",

design : "com.android.support:design:$versions.supportLibrary",

recyclerviewv7: "com.android.support:recyclerview-v7:$versions.supportLibrary"

]

Refactor Your Dependencies

app/build.gradle

apply from: ‘../dependencies.gradle’

dependencies {

compile supportDependencies.appcompatv7

compile supportDependencies.design

compile supportDependencies.recyclerviewv7

}

Use “apply from”

jacoco.gradle

apply plugin: 'jacoco'

jacoco {

toolVersion = versions.jacoco

}

project.afterEvaluate {

...

}

app/build.gradle

apply from: '../jacoco.gradle'

Know Thy Tools!

Master Command Line

Print exception stacktrace (--stacktrace)

./gradlew assemble -s

Print INFO logs (--info)

./gradlew assemble -i

Print DEBUG logs (--debug)

./gradlew assemble -d

Master Command Line

Force offline execution

./gradlew assemble --offline

Force Gradle to re-download dependencies

./gradlew assemble --refresh-dependencies

Where Does a Dependency Come From?

Displays all dependencies declared in project

./gradlew -q :app:dependencies

Displays the Android dependencies of the project

./gradlew -q :app:androidDependencies

Where Does a Dependency Come From?

The Mysterious Asterisk

Getting More Insight

Displays the insight into a specific dependency in project

./gradlew -q :app:dependencyInsight --configuration compile --dependency okhttp

Getting More Insight

Use buildConfigFields

buildTypes {

debug {

...

buildConfigField 'long', 'UPDATE_FREQUENCY_MILLIS', '600000' // 10m

}

release {

...

buildConfigField 'long', 'UPDATE_FREQUENCY_MILLIS', '86400000' // 24h

}

}

Store Sensitive Info in gradle.properties

~/.gradle/gradle.properties

SuperSecretKey=this-is-a-super-secret-key

app/build.gradle

buildTypes.each {

it.buildConfigField 'String', 'SUPER_SECRET_KEY', SuperSecretKey

}

MainActivity.java

String secretKey = BuildConfig.SUPER_SECRET_KEY;

Exclude Resource Configurations

buildTypes { release { ... resConfigs "en", "de" }}

Limit resources to English and German localizations

Exclude Resource Configurations

buildTypes { release { ... resConfigs "auto" }}

Limit resources to project localizations

Share Test Code Between Test Types

android {

sourceSets {

String sharedTestDir = 'src/sharedTest/java'

test {

java.srcDir sharedTestDir

}

androidTest {

java.srcDir sharedTestDir

}

}

}

http://blog.danlew.net/2015/11/02/sharing-code-between-unit-tests-and-instrumentation-tests-on-android/

Thank You!Egor Andreevici

Software Developer at 1&1

blog.egorand.me | @EgorAnd | +EgorAndreevich