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

Level Up your Android Build - DevoxxUK 2015

Avatar for Volker Volker
June 19, 2015

Level Up your Android Build - DevoxxUK 2015

Slides from my talk at DevoxxUK.

Avatar for Volker

Volker

June 19, 2015

Other Decks in Technology

Transcript

  1. @devisnik #AndroidBuild app/build.gradle apply plugin: 'com.android.application' android { compileSdkVersion 22

    buildToolsVersion '22.2.0' defaultConfig { ... } buildTypes { release { ... } } } dependencies { ... }
  2. @devisnik #AndroidBuild Relevant Build Files ├── app │ └── build.gradle

    ├── build.gradle ├── gradle │ └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── local.properties └── settings.gradle
  3. @devisnik #AndroidBuild Using a Gradle plugin /build.gradle buildscript { repositories

    { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.2.3' classpath 'com.novoda:gradle-android-command-plugin:1.4.0' } } /app/build.gradle apply plugin: 'com.novoda.android-command' $ gw runDebug
  4. @devisnik #AndroidBuild Dependencies apply plugin: 'com.neenbedankt.android-apt' dependencies { apt 'com.google.dagger:dagger-compiler:2.0'

    compile 'com.google.dagger:dagger:2.0' compile 'com.google.guava:guava:18.0' testCompile 'junit:junit:4.12' testCompile 'org.mockito:mockito-core:1.9.5' }
  5. @devisnik #AndroidBuild Dependencies apply plugin: 'com.neenbedankt.android-apt' dependencies { apt 'com.google.dagger:dagger-compiler:2.0'

    compile 'com.google.dagger:dagger:2.0' compile 'com.google.guava:guava:18.0' paidCompile project(':lvl') testCompile 'junit:junit:4.12' testCompile 'org.mockito:mockito-core:1.9.5' }
  6. @devisnik #AndroidBuild Proguard buildTypes { release { minifyEnabled true shrinkResources

    true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.cfg' } } proguard.cfg #Dagger2 -dontwarn dagger.shaded.auto.common.** -dontwarn dagger.internal.codegen.** -keepattributes Signature
  7. @devisnik #AndroidBuild Archive Release ext.VERSION_NAME=1.0.0 ... task archiveRelease(type: Copy) {

    from 'build/outputs/apk', 'build/outputs/' into "releases/${VERSION_CODE}" include('android-release.apk', 'mapping/**') rename ('android-release.apk', "${APP_NAME}_${BUILD_DATE}_${VERSION_NAME}_${VERSION_CODE}.apk") }
  8. @devisnik #AndroidBuild Scaling up • re-use • testing • quality

    assurance • continuous integration • push-button release
  9. @devisnik #AndroidBuild gradle init --type java-library dependencies { compile project(':model')

    } gradle init --type groovy-library def url = new URL('https://api.github.com/users/devisnik/starred') def json = new JsonSlurper().parseText(url.text) println json*.name Re-use - Playground project
  10. @devisnik #AndroidBuild Testing - Integration Tests in Core sourceSets {

    integrationTest { java { srcDir 'src/integrationtest/java' } resources { srcDir 'src/integrationtest/resources' } compileClasspath += sourceSets.main.runtimeClasspath } } task integrationTest(type: Test) { testClassesDir = sourceSets.integrationTest.output.classesDir classpath += sourceSets.integrationTest.runtimeClasspath }
  11. @devisnik #AndroidBuild Keeping Up To Date apply plugin: 'com.github.ben-manes.versions' $

    gw dependencyUpdates The following dependencies have later milestone versions: - com.fasterxml.jackson.core:jackson-annotations [2.1.2 -> 2.6.0- rc1] - com.fasterxml.jackson.core:jackson-core [2.1.1 -> 2.6.0-rc1] - com.fasterxml.jackson.core:jackson-databind [2.1.2 -> 2.6.0-rc1] - com.github.kevinsawicki:http-request [4.0 -> 9.9] - joda-time:joda-time [2.3 -> 2.8] - org.mockito:mockito-core [1.9.0 -> 2.0.8-beta] Generated report file build/dependencyUpdates/report.txt
  12. @devisnik #AndroidBuild Code Quality Tools apply plugin: 'checkstyle' task checkstyleMain(

    type: Checkstyle) { description 'Checks whether code complies with coding rules.' ignoreFailures !project.failFastOnError ... doLast { if (project.hasProperty('checkstyle.html')) { ant.xslt(in: reports.xml.destination, style: file("$rulesDir/checkstyle/noframes-sorted. xsl"), out: new File(reports.xml.destination.parent, name - 'checkstyle' + '.html')) } } }
  13. @devisnik #AndroidBuild Code Quality Tools apply plugin: 'checkstyle' task checkstyleMain(type:

    Checkstyle) { description 'Checks whether code complies with coding rules.' ignoreFailures !project. failFastOnError ... doLast { if (project.hasProperty(' checkstyle.html')) { ant.xslt(in: reports.xml.destination, style: file("$rulesDir/checkstyle/noframes-sorted. xsl"), out: new File(reports.xml.destination.parent, name - 'checkstyle' + '.html')) } } } $ gw checkstyleMain -PfailFastOnError -Pcheckstyle.html
  14. @devisnik #AndroidBuild Code Quality Tools apply plugin: 'checkstyle' task checkstyleMain(type:

    Checkstyle) { description 'Checks whether code complies with coding rules.' ignoreFailures !project.failFastOnError ... doLast { if (project.hasProperty('checkstyle.html')) { ant.xslt(in: reports.xml.destination, style: file("$rulesDir/checkstyle/noframes-sorted. xsl"), out: new File(reports.xml.destination.parent, name - 'checkstyle' + '.html')) } } }
  15. @devisnik #AndroidBuild Updating the Android SDK apply plugin: 'android-sdk-manager' $

    gw assembleDebug Android SDK not found. Downloading... > Configuring > 1/5 projects > :android SDK extracted at '/Users/leck/.android-sdk'. Writing to local. properties. Build tools 21.1.2 missing. Downloading... > Configuring > 2/5 projects Platform tools missing. Downloading... Compilation API android-21 missing. Downloading… ...
  16. @devisnik #AndroidBuild Connected Tests on CI task filterTestDevices << {

    com.android.builder.testing. ConnectedDeviceProvider.metaClass .getDevices = { localDevices .findAll { it.iDevice.online } .findAll { !it.getProperty('ro.build.characteristics') ?.toLowerCase()?.contains('tablet') } .unique { it.apiLevel } } }
  17. @devisnik #AndroidBuild Connected Tests on CI afterEvaluate { project.tasks.findAll {

    it.name.startsWith('connectedAndroidTest') }*.dependsOn filterTestDevices }
  18. @devisnik #AndroidBuild Release from CI - Versioning def versionFile =

    file('version.properties') Version version = Version.read(versionFile) task incrementVersion << { Version.increment(versionFile) }
  19. @devisnik #AndroidBuild Release from CI - Versioning def versionFile =

    file('version.properties') Version version = Version.read(versionFile) task incrementVersion << { Version.increment(versionFile) } buildSrc └── src └── main └── groovy └── Version.groovy
  20. @devisnik #AndroidBuild Release from CI - git buildscript { dependencies

    { classpath 'org.ajoberstar:grgit:1.1.0' } } ext { git = org.ajoberstar.grgit.Grgit.open( rootProject.file('.')) } def sha = git.head().abbreviatedId git.add 'version.properties' git.commit(message: "Bumping version to $VERSION_CODE") git.push()
  21. @devisnik #AndroidBuild Shared Build Logic share common configuration data via

    root build.gradle File rules(String relativeFilePath) { file("shared/rules/$relativeFilePath") } app/build.gradle: findbugs { excludeFilter rules('findbugs/exclude.xml') ... }
  22. @devisnik #AndroidBuild Shared Build Logic share common dependencies via root

    build.gradle ext { guava_lib = 'com.google.guava:guava:18.0' ... testing_libs = [junit_lib, assertJ_lib] } use it in sub-projects via: dependencies { compile guava_lib ... testCompile testing_libs }
  23. @devisnik #AndroidBuild Shared Build Logic android { … buildTypes {

    debug { buildConfigField 'String', 'TAG' ,'"DEBUG_TAG"' } release { buildConfigField 'String', 'TAG' ,'"RELEASE_TAG"' } } } android.buildTypes.all { ext.tag = { tag -> buildConfigField 'String', 'TAG', '"'+ tag +'"' } } buildTypes { debug { tag 'DEBUG_TAG' } release { tag 'RELEASE_TAG' } }
  24. @devisnik #AndroidBuild Library Shrinking dependencies { classpath 'net.sf.proguard:proguard-gradle:4.11' } ...

    task shrinkGuava(type: proguard.gradle.ProGuardTask) { injars configurations.injar.files libraryjars configurations.libjar.files outjars file("build/libs/guava_${guavaVersion}_base.jar") configuration 'guava.proguard' } guava.proguard: -dontoptimize -dontobfuscate -keep public class com.google.common.base.** { public *; }
  25. @devisnik #AndroidBuild Sync images task syncPhotos(type: com.novoda.gradle.command.Files) { deviceId {

    def moto = android.command.devices().find { it.brand() == 'motorola' } moto.id } script { def backupDir = mkdir 'motoPhoto' list('/sdcard/DCIM/Camera/').findAll { image -> !new File(backupDir.path, image.name).exists() }.each { image -> pull image.path + image.name, backupDir.path } } }
  26. @devisnik #AndroidBuild Sqlite Access sqliteAccess { migrationsDir 'src/main/assets/migrations' packageName 'com.novoda.sqliteprovider.demo.simple'

    generator { database, basedir -> def access = access(database) // adjust access model as needed generateClass(file('code.template'), access, 'DB', packageName, basedir) } }
  27. @devisnik #AndroidBuild Sqlite Access sqliteAccess { migrationsDir 'src/main/assets/migrations' packageName 'com.novoda.sqliteprovider.demo.simple'

    generator { database, basedir -> def access = access(database) // adjust access model as needed generateClass(file('code.template'), access, 'DB', packageName, basedir) } }
  28. @devisnik #AndroidBuild Sqlite Access code.template package $packageName; public final class

    $className { public static final class Tables { <% access.tables.each { dataSet -> %> public static final String $dataSet.name = "$dataSet. sqlName"; <% } %> } ... }
  29. @devisnik #AndroidBuild Groovy on Android buildscript { repositories { jcenter()

    } dependencies { classpath 'com.android.tools.build:gradle:1.1.0' classpath 'org.codehaus.groovy:gradle-groovy-android-plugin:0.3.6' } } apply plugin: 'groovyx.grooid.groovy-android' dependencies { compile 'org.codehaus.groovy:groovy:2.4.3:grooid' }
  30. @devisnik #AndroidBuild TDTD - Tester-Driven Talk Development Thanks to the

    folks from Android Stammtisch Berlin for serving as Testers for a lot of the presented material. Upcoming book: Growing Subject-Oriented Talks, Guided by Testers
  31. @devisnik #AndroidBuild Resources (in order of appearance) Gradle https://github.com/gradle/gradle Android

    plugin for Gradle https://developer.android.com/tools/building/plugin-for-gradle.html gdub Tool https://github.com/dougborg/gdub Command Plugin https://github.com/novoda/gradle-android-command-plugin Gradle Plugin Portal http://plugins.gradle.org
  32. @devisnik #AndroidBuild Resources (in order of appearance) apt Plugin https://bitbucket.org/hvisser/android-apt

    Proguard Annotation Squadleader https://bitbucket.org/littlerobots/squadleader Proguard Snippets https://github.com/krschultz/android-proguard-snippets Gradle Udacity Course https://www.udacity.com/course/gradle-for-android-and-java--ud867
  33. @devisnik #AndroidBuild Resources (in order of appearance) Versions Plugin https://github.com/ben-manes/gradle-versions-plugin

    Code Analysis Plugin https://github.com/dlabs/soter Groovy library for git https://github.com/ajoberstar/grgit SDK Manager Plugin https://github.com/JakeWharton/sdk-manager-plugin
  34. @devisnik #AndroidBuild Resources (in order of appearance) Shrink Guava Script

    Snippet https://gist.github.com/devisnik/e54ea0a629adc82bcfa0 DexCount https://github.com/KeepSafe/dexcount-gradle-plugin Sqlite Analyzer Plugin https://github.com/novoda/sqlite-analyzer Groovy Android Plugin https://github.com/groovy/groovy-android-gradle-plugin