#babbqamsterdam the other android getting started guide: gradle power

43
THE OTHER ANDROID GETTING STARTED GUIDE: GRADLE POWER

Upload: javier-de-pedro-lopez

Post on 12-Apr-2017

552 views

Category:

Engineering


6 download

TRANSCRIPT

Page 1: #BABBQAmsterdam The other Android getting started guide: Gradle power

THE OTHER ANDROID GETTING STARTED GUIDE: GRADLE POWER

Page 2: #BABBQAmsterdam The other Android getting started guide: Gradle power

Javier de Pedro López

StrengthsExperience

Android Developer at Mobgen

2 Years professionally 2 Different companies

Time spent in 4 Projects Free time

Design Patterns Gradle

Clean architecture Code quality

@droidpl [email protected] [email protected]

Page 3: #BABBQAmsterdam The other Android getting started guide: Gradle power

`Why the other getting started guide?

Beginner Junior

Medior

Getting started

The other getting started

Page 4: #BABBQAmsterdam The other Android getting started guide: Gradle power

This talk

Gradle in Android

Continuous Integration

Android Testing and

Unit testing

Code coverage DocumentationPut it all together

Page 5: #BABBQAmsterdam The other Android getting started guide: Gradle power

GRADLE IN ANDROID: THE PLUGIN UNIVERSE Round 1

Page 6: #BABBQAmsterdam The other Android getting started guide: Gradle power

• Google I/O 2013 (Android Studio)

• Gradle: default build system

• Configuration in Groovy

• Gradle version 2.4 (out of 2.8)

• Android plugin 1.3.0 (exp 1.5.0-beta1)

Gradle in Android

Context

The project

Closures / DSL

TASKS

Page 7: #BABBQAmsterdam The other Android getting started guide: Gradle power

Gradle in Android

Context

The project

Closures / DSL

TASKS

/—— (project) —build.gradle —settings.gradle —/app (module)

—build.gradle

Android Studio Project

gradle project ($project)

apply from apply plugin

android { }

org.gradle.api.Project

root project ($rootProject)allprojects

Page 8: #BABBQAmsterdam The other Android getting started guide: Gradle power

Gradle in Android

The project

Closures / DSL

TASKS

Context

myExtension { test true inner { test false } }

DSL (Domain Specific Language)class MyExtension { InnerObject obj def test(boolean value){} def inner(Closure closure){ project.configure(obj, closure) } }

Closure

project.task(‘copy’, type: Copy, Closure)

task('copy', type: Copy) { from(file('srcDir')) into(buildDir) }

Plugin extension

project.extensions.create(‘android”, Ex)

android {

}

Page 9: #BABBQAmsterdam The other Android getting started guide: Gradle power

Gradle in Android

The project

Closures / DSL

TASKS

Context

Android DSLandroid { ...

... }

buildTypes { debug { } release { }

}

Build types

productFlavors { pro {

dimension 'version' } x86 {

dimension ‘abi' }

}

Flavors

flavorDimensions 'abi', 'version' Dimensions

Variant == Flavor(s) + BuildType

Page 10: #BABBQAmsterdam The other Android getting started guide: Gradle power

Gradle in Android

The project

Closures / DSL

TASKS

Context

org.gradle.api.Task

Execute task

./gradlew app:myTask

Android StudioDefine tasks

task mytask << { println "Ending" }

mytask.doFirst { println "Beginning" }

mytask.dependsOn(assembleDebug)

Page 11: #BABBQAmsterdam The other Android getting started guide: Gradle power

Gradle in Android

The project

Closures / DSL

TASKS

Context

Sample execution (mytask). . . :app:generateDebugResValues UP-TO-DATE :app:generateDebugResources UP-TO-DATE :app:mergeDebugResources UP-TO-DATE :app:processDebugManifest UP-TO-DATE :app:processDebugResources UP-TO-DATE :app:generateDebugSources UP-TO-DATE :app:processDebugJavaRes UP-TO-DATE :app:compileDebugJavaWithJavac :app:compileDebugNdk UP-TO-DATE :app:compileDebugSources :app:preDexDebug :app:dexDebug :app:validateDebugSigning :app:packageDebug :app:zipalignDebug :app:assembleDebug :app:mytask Beginning Ending

Page 12: #BABBQAmsterdam The other Android getting started guide: Gradle power

CONTINUOUS INTEGRATION TIPSRound 2

You shall not pass

Page 13: #BABBQAmsterdam The other Android getting started guide: Gradle power

CI Tips

CI version code

ci Version name

WhyAndroid versioning problemandroid { ... defaultConfig { versionCode 1

versionName "1.0-SNAPSHOT" } ... }

“Be a hater of hardcoded values, if you can get rid of them"

Solution

• Use your repository for versioning• Use gradle to be smart

Page 14: #BABBQAmsterdam The other Android getting started guide: Gradle power

CI Tips

CI version code

ci Version name

WhyCount the commit

Android Version code == commit number (why not?)

Code

final String COMMAND = "git rev-list HEAD --first-parent —count"

public int getCommitRevision(){ def count = 0 def commitNumber = COMMAND.execute().text if(!commitNumber.isEmpty()){ count = commitNumber.toInteger() } return count }

Page 15: #BABBQAmsterdam The other Android getting started guide: Gradle power

Version name

1.0.134(-SNAPSHOT)

CI Tips

ci Version Name

Why

CI version code

public String getTag(){ def tag = "git describe".execute().text.trim() if(tag.isEmpty()){ tag = "v0" } return tag }

//BAMBOO or other CI system def CI_BUILD = System.getenv(“bamboo_buildNumber")

def version = "${getTag}.$CI_BUILD" gradle.taskGraph.whenReady { taskGraph -> if(taskGraph.hasTask(assembleDebug)) { version += "-SNAPSHOT" } }

Page 16: #BABBQAmsterdam The other Android getting started guide: Gradle power

UNIT TESTING AND ANDROID TESTINGRound 3

Android testing (espresso,...) Unit testing (JUnit)

Page 17: #BABBQAmsterdam The other Android getting started guide: Gradle power

Android testing / Unit testingWhy two types

Android Testing

Unit Testing

CI tasks

Unit testing

Pros• Runs on the JVM • Uses JUnit • Is lightning fast • Allows TDD

Cons• No real views • Have to mock android.jar

Android testing

Pros• You can have a coffee • Test views • Activity lifecycle • Real behaviour

Cons• SLOW, seriously • Needs a device • Difficult to setup the CI • Automation

The android.jar trouble

Page 18: #BABBQAmsterdam The other Android getting started guide: Gradle power

Why two types

Android Testing

Unit Testing

CI tasks

• Goes in the src/androidTest folder

• Extend from: ApplicationTestCase, ActivityInstrumentationTestCase2, ActivityUnitTestCase, ServiceTestCase, ProviderTestCase

• Use libraries: AndroidJUnitRunner: JUnit compatible test runner UIAutomator: System tests Espresso: UI testing

Android testing / Unit testing

Page 19: #BABBQAmsterdam The other Android getting started guide: Gradle power

Why two types

Android Testing

Unit TestingCI tasks

• Goes in the src/test folder

• Uses jUnit 4 standard @Test.

• You can use the default runner@RunWith(BlockJUnit4ClassRunner.class)

• Robolectric 3 (gradle support) @RunWith(RobolectricGradleTestRunner.class) @Config(constants = BuildConfig.class, sdk = 21, manifest = "src/main/AndroidManifest.xml")

Android testing / Unit testing

Page 20: #BABBQAmsterdam The other Android getting started guide: Gradle power

Why two types

Android Testing

Unit Testing

CI tasksCI Unit test tasks//One variant ./gradlew app:test{flavor}{buildType}UnitTest

// All variants ./gradlew app:test

CI Android test task//Variant ./gradlew app:connected{flavor}{buildType}AndroidTest

//All flavours ./gradlew app:connectedAndroidTest

//All checks ./gradlew app:connectedCheck

Android testing / Unit testing

Page 21: #BABBQAmsterdam The other Android getting started guide: Gradle power

CODE COVERAGE WITH JACOCO: NOW IN THE JVMRound 4

Page 22: #BABBQAmsterdam The other Android getting started guide: Gradle power

Code coverage

Coverage on Android tests

Coverage on Unit tests

Simply works

• Enable it in the build type • Execute the task • Report located on build/reports/coverage/{flavor}/{buildtype}/

testCoverageEnabled true

Report

Merge reports

CI tasks

Page 23: #BABBQAmsterdam The other Android getting started guide: Gradle power

Code coverage

Coverage on Android tests

Coverage on Unit tests

Not covered (yet)

• https://code.google.com/p/android/issues/detail?id=144664 • Manual task

Merge reports

CI tasks

Gradle saves the day

Page 24: #BABBQAmsterdam The other Android getting started guide: Gradle power

Code coverage

Coverage on Android tests

Coverage on Unit tests

Merge reports

CI tasks

sourceDirectories = files("src/main/java", "src/debug/java") executionData =

files("$buildDir/jacoco/test$variantNameUnitTest.exec") reports { xml.enabled = false html.enabled = true }

Jacoco report tasktask (name: “create${variantName}UnitTestCoverageReport”,

type: JacocoReport, dependsOn: "test${variantName}UnitTest") {

}

def classes = "$buildDir/intermediates/classes/$flavor/$buildType" classDirectories = project.fileTree( dir: "${baseLocation}", excludes: ['**/R.class', '**/R$*.class', '**/*$ViewInjector*.*', '**/BuildConfig.*', '**/Manifest*.*', '**/*_*Factory.*'] )

Page 25: #BABBQAmsterdam The other Android getting started guide: Gradle power

Code coverage

Coverage on Android tests

Coverage on Unit tests

Merge reports

CI tasks CI Unit test coverage tasks

Task name provided:./gradlew app:create{flavor}{buildType}UnitTestCoverageReport

CI Android test coverage tasks./gradlew app:create{flavor}{buildType}AndroidTestCoverageReport

ONLY AVAILABLE FOR DEBUG

Page 26: #BABBQAmsterdam The other Android getting started guide: Gradle power

Code coverage

Coverage on Android tests

Coverage on Unit tests

What if…

"I want one report to rule them all"

Gradle againproject.afterEvaluate { def dest = "$buildDir/outputs/code-coverage/connected/coverage.ec" testDebugUnitTest.jvmArgs "-javaagent:$buildDir/intermediates/jacoco/jacocoagent.jar=append=true,destfile=$destfile" createDebugAndroidTestCoverageReport.dependsOn testDebugUnitTest }

Merge reports

CI tasks

./gradlew clean createDebugAndroidTestCoverageReport

Page 27: #BABBQAmsterdam The other Android getting started guide: Gradle power

CODE QUALITYRound 5

Page 28: #BABBQAmsterdam The other Android getting started guide: Gradle power

Code QUAlity

sonarQube

Configuration

CI Tasks

• Provides metrics

• Supports Android

• Reports issues by priority

• Integrates with JIRA, Mantis…

• Implements SQALE

Page 29: #BABBQAmsterdam The other Android getting started guide: Gradle power

Code QUAlity

sonarQube

Configuration

CI Tasks

SonarQube task

apply plugin : "sonar-runner"

task (name:"codeQuality", dependsOn: "test${variantName}UnitTestCoverageRepor") {

}

sonarRunner { sonarProperties {

$PROPERTIES } }project.findByName("sonarRunner").execute()

doLast {

}

Page 30: #BABBQAmsterdam The other Android getting started guide: Gradle power

Code QUAlity

sonarQube

Configuration

CI Tasks

SonarQube task

property "sonar.host.url", “$sonarHost" property "sonar.projectKey", "$sonarProjectKey" property "sonar.projectName", "$sonarProjectName"

property "sonar.jdbc.url", "$databaseHost" property "sonar.jdbc.driverClassName", "$databaseDriver" property "sonar.jdbc.username", "$databaseUsername" property "sonar.jdbc.password", "$databasePassword"

property "sonar.sources", "$SOURCES" property "sonar.binaries", "${project.buildDir}/$BINARIES/$flavorName/$buildTypeName" property "sonar.jacoco.reportPath", "${project.buildDir}$JACOCO_PATH/test${variantName}UnitTest.exec"

private final String BINARIES = "/intermediates/classes" private final String JACOCO_PATH = "/jacoco" private final String SOURCES = "src/main"

Page 31: #BABBQAmsterdam The other Android getting started guide: Gradle power

Code QUAlity

Configuration

CI Tasks

sonarQube

CI execution tasks

./gradlew app:codeQuality

Task name provided:

Page 32: #BABBQAmsterdam The other Android getting started guide: Gradle power

DOCUMENTATION: WHY NOT DOCLAVA?Round 6

Page 33: #BABBQAmsterdam The other Android getting started guide: Gradle power

DOcumentation

vs javadoc

Configuration

CI Tasks

• Enhanced look and feel

• Versioning inside documentation

• Customizations using templates

• Embedding in bigger pages

• Extended markup (@hide, @undeprecate…)

Page 34: #BABBQAmsterdam The other Android getting started guide: Gradle power

DOcumentation

vs javadoc

Configuration

CI Tasks

Doclava task

project.configurations { docLava }

project.dependencies { docLava "com.google.doclava:doclava:1.0.6" }

Page 35: #BABBQAmsterdam The other Android getting started guide: Gradle power

DOcumentation

vs javadoc

Configuration

CI Tasks

Doclava taskproject.task("create${variantName}Documentation", type: Javadoc) {

}

options { addStringOption "templatedir", "$yourTemplateDir" doclet “com.google.doclava.Doclava"

bootClasspath new File(System.getenv('JAVA_HOME') + "/jre/lib/rt.jar")

docletpath = project.configurations.docLava.files.asType(List) }

title = null

source = variant.javaCompile.source ext.androidJar = “${project.android.sdkDirectory}/platforms/“ +

“${project.android.compileSdkVersion}/android.jar"

classpath = project.files(variant.javaCompile.classpath.files) + project.files(ext.androidJar)

exclude '**/BuildConfig.java' exclude '**/R.java'

Page 36: #BABBQAmsterdam The other Android getting started guide: Gradle power

DOcumentation

vs javadoc

Configuration

CI Tasks

CI execution tasks

./gradlew app:create{flavor}{buildType}Documentation

Task name provided:

Page 37: #BABBQAmsterdam The other Android getting started guide: Gradle power

PLUGIN: ALL TOGETHERRound 7

Page 38: #BABBQAmsterdam The other Android getting started guide: Gradle power

Plugin

how to create one

grill (ALPHA)

Create a groovy project• src/main/groovy• apply plugin: “groovy" • Add dependencies

Declare the plugin• Create src/main/resources/META-INF/gradle-plugins• Choose a name for the plugin • Create name.properties • Add: implementation-class=class.name.of.Plugin

Declare the plugin

• apply plugin: “maven” • ./gradlew plugin:install • apply plugin: "myCustomPlugin"

Page 39: #BABBQAmsterdam The other Android getting started guide: Gradle power

Plugin

how to create one

grill (alpha)

BBQ Grill Android Plugin https://github.com/droidpl/GrillPlugin

DSL for quality projects

grill { CI { $PROPERTIES } testing { $PROPERTIES } codeQuality { $PROPERTIES } documentation { $PROPERTIES } }

• Multiple variants

• Libraries and apps

• Many tools - one place

Page 40: #BABBQAmsterdam The other Android getting started guide: Gradle power

Conclusions (CI)

Unit testing

test$variantUnitTest

Android Testingconected$variant

AndroidTest

Unit Testing Code coverage

create$variantUnit TestCoverageReport

Android Testing Code coverage

create$variantAndroid TestCoverageReport

quality

codeQuality

documentationcreate$variant Documentation

Page 41: #BABBQAmsterdam The other Android getting started guide: Gradle power

Conclusions

Gradle IS OUR FRIEND

Multiple variants PROBLEMS

Configuring everything is hard

Quality measurements matters

Testing EVERYTHING IS possible

Take care of your build logic

Page 42: #BABBQAmsterdam The other Android getting started guide: Gradle power

……………………Q&A

Page 43: #BABBQAmsterdam The other Android getting started guide: Gradle power

……………………Thank you!