Level Up Your Android Build -Droidcon Berlin 2015
-
Upload
friedger-mueffke -
Category
Mobile
-
view
405 -
download
5
Transcript of Level Up Your Android Build -Droidcon Berlin 2015
Level Up Your Android Build - droidcon Berlin 2015
LEVEL UP YOUR ANDROID BUILDVolker Leck
Friedger Müffke
Droidcon Berlin 2015
Level Up Your Android Build - droidcon Berlin 2015
image
Level Up Your Android Build - droidcon Berlin 2015
image
Phoogle Gotos
Level Up Your Android Build - droidcon Berlin 2015
app/build.gradleapply plugin: 'com.android.application'
android { compileSdkVersion 22 buildToolsVersion "22.2.0"
defaultConfig {...
} buildTypes { release {
... } }}
dependencies {...
}
Level Up Your Android Build - droidcon Berlin 2015
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
Level Up Your Android Build - droidcon Berlin 2015
Gradle wrapper$ ./gradlew tasks
Level Up Your Android Build - droidcon Berlin 2015
Gradle wrapper$ gw clean ass
Level Up Your Android Build - droidcon Berlin 2015
Using a Gradle pluginbuild.gradle (root folder)
buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.2.3'
classpath 'com.novoda:gradle-android-command-plugin:1.4.0' }}
apply plugin: 'com.novoda.android-command'
$ gw runDebug
Level Up Your Android Build - droidcon Berlin 2015
Dependencies
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' }
Level Up Your Android Build - droidcon Berlin 2015
Dependencies
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' }
Level Up Your Android Build - droidcon Berlin 2015
Flavors (free - paid)
Level Up Your Android Build - droidcon Berlin 2015
ProguardbuildTypes { 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
Level Up Your Android Build - droidcon Berlin 2015
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")}
Level Up Your Android Build - droidcon Berlin 2015
image
Level Up Your Android Build - droidcon Berlin 2015
image
Level Up Your Android Build - droidcon Berlin 2015
Scaling up● re-use● testing● quality assurance● continuous integration
Level Up Your Android Build - droidcon Berlin 2015
Re-use - Core project
gradle init --type java-library
dependencies { compile project(':model')}
Level Up Your Android Build - droidcon Berlin 2015
Re-use - Core project
gradle init --type java-library
dependencies { compile project(':model')}
gradle init --type groovy-library
println new URL('http://www.google.com').text
Level Up Your Android Build - droidcon Berlin 2015
Separation - Integration Tests for JavasourceSets {
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
}
Level Up Your Android Build - droidcon Berlin 2015
Keep Up To Date
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
Level Up Your Android Build - droidcon Berlin 2015
Code Quality Toolsapply 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')) } }}
Level Up Your Android Build - droidcon Berlin 2015
Code Quality Toolsapply 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
Level Up Your Android Build - droidcon Berlin 2015
Code Quality Toolsapply 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')) } }}
Level Up Your Android Build - droidcon Berlin 2015
Continuous IntegrationSystem.getenv("...")
Jenkins
BUILD_NUMBER
Travis
TRAVIS_BUILD_NUMBER
Level Up Your Android Build - droidcon Berlin 2015
Connected Tests on CItask 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 } }}
Level Up Your Android Build - droidcon Berlin 2015
Connected Tests on CI
afterEvaluate { project.tasks.findAll {
it.name.startsWith('connectedAndroidTest') }*.dependsOn filterTestDevices
}
Level Up Your Android Build - droidcon Berlin 2015
Releasing from CI
● update Version
● commit changes
● upload to Stores
Level Up Your Android Build - droidcon Berlin 2015
Release from CI - Versioning
def versionFile = file('version.properties')
Version version = Version.read(versionFile)
task incrementVersion << { Version.increment(versionFile)}
Level Up Your Android Build - droidcon Berlin 2015
Release from CI - Versioning
def versionFile = file('version.properties')
Version version = Version.read(versionFile)
task incrementVersion << { description = 'Increases the version' Version.increment(versionFile)}
buildSrc/└── src └── main └── groovy └── Version.groovy
Level Up Your Android Build - droidcon Berlin 2015
Release from CI - gitbuildscript { dependencies { classpath 'org.ajoberstar:grgit:1.1.0' }}ext { git = org.ajoberstar.grgit.Grgit.open(
rootProject.file('.'))}def sha = git.head().abbreviatedIdgit.add 'version.properties' git.commit(message: "Bumping version to $VERSION_CODE")git.push()
Level Up Your Android Build - droidcon Berlin 2015
Publishing - Google Playplay-publisher-plugin by triple-t● bootstrapReleasePlayResources - Fetch all existing data from the Play
Store to bootstrap the required files and folders.● publishApkRelease - Uploads the APK and the summary of recent
changes.● publishListingRelease - Uploads the descriptions and images for the Play
Store listing.● publishRelease - Uploads everything.
Level Up Your Android Build - droidcon Berlin 2015
Publishing - Google Playplay-publisher-plugin by triple-t● bootstrapReleasePlayResources - Fetch all existing data from the Play
Store to bootstrap the required files and folders.● publishApkRelease - Uploads the APK and the summary of recent
changes.● publishListingRelease - Uploads the descriptions and images for the Play
Store listing.● publishRelease - Uploads everything.play {
serviceAccountEmail = 'your-service-account-email' pk12File = file('key.p12')}
Level Up Your Android Build - droidcon Berlin 2015
Publishing - Other App Stores
task createAppDFs {
android.applicationVariants.all { variant ->
if (variant.buildType.name == "release")
createAppDF(variant.name)
}
}
Level Up Your Android Build - droidcon Berlin 2015
Advanced - Complex Build Scriptsshare common configuration data via root subfolder
File shared(String relativeFilePath) { file("shared/$relativeFilePath")
}
share common dependencies via root build.gradleext {
guavaDependency = 'com.google.guava:guava:18.0'...
}
use it in sub-projects via:dependencies {
compile guavaDependency...
}
Level Up Your Android Build - droidcon Berlin 2015
Advanced - Shrinkdependencies { 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 *; }
Level Up Your Android Build - droidcon Berlin 2015
Advanced - Sync imagestask syncPhotos(type: com.novoda.gradle.command.Files) { deviceId { def moto = android.command.devices().find { it.brand() == 'motorola' } if (!moto) { throw new GroovyRuntimeException('No Motorola device') } 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 } }}
Level Up Your Android Build - droidcon Berlin 2015
Advanced - Sqlite AccesssqliteAccess { 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) }}
Level Up Your Android Build - droidcon Berlin 2015
Advanced - Sqlite Accesscode.template
package $packageName;
public final class $className {public static final class Tables {
<% access.tables.each { dataSet -> %> public static final String $dataSet.name = "$dataSet.sqlName";<% } %>
}...
}
Level Up Your Android Build - droidcon Berlin 2015
Advanced - Groovy on Androidbuildscript { 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'}
Level Up Your Android Build - droidcon Berlin 2015
Resources (in order of appearance)Android plugin for Gradle
https://developer.android.com/tools/building/plugin-for-gradle.html
gdub Tool
https://github.com/dougborg/gdub
apt Plugin
https://bitbucket.org/hvisser/android-apt
Command Plugin
https://github.com/novoda/gradle-android-command-plugin
Gradle Plugin Portal
http://plugins.gradle.org
Level Up Your Android Build - droidcon Berlin 2015
Resources (in order of appearance)Proguard Annotation Squadleader
https://bitbucket.org/littlerobots/squadleader
Proguard Snippets
https://github.com/krschultz/android-proguard-snippets
Gradle Udacity Course
https://www.udacity.com/wiki/ud867
Groovy library for git
https://github.com/ajoberstar/grgit
Level Up Your Android Build - droidcon Berlin 2015
Resources (in order of appearance)Soter Plugin
https://github.com/dlabs/soter
Shrink Guava Script Snippet
https://gist.github.com/devisnik/e54ea0a629adc82bcfa0
Groovy Android Plugin
https://github.com/groovy/groovy-android-gradle-plugin
Sqlite Analyzer Plugin
https://github.com/novoda/sqlite-analyzer
Level Up Your Android Build - droidcon Berlin 2015
TDTD - Tester-Driven Talk DevelopmentThanks 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
Level Up Your Android Build - droidcon Berlin 2015
Friedger Müffke Volker Leck
fmdroid devisnik
+FriedgerMüffke +VolkerLeck
friedger devisnik
Level Up Your Android Build - droidcon Berlin 2015
Build tooling
Level Up Your Android Build - droidcon Berlin 2015
Problems● no re-use outside android app● limited and manual code quality assurance (via test feedback)● limited automation
○ manual versioning○ manual deployment○ no continuous integration○ tedious distribution (beta channels, bug tracking, ..)○ dependent on Android SDK installation
Level Up Your Android Build - droidcon Berlin 2015
Separation - Test Executiontest { useJUnit { excludeCategories 'com.sample.api.LiveTest' }}task endpointTest(type: Test, dependsOn: testClasses) { useJUnit { includeCategories 'com.sample.api.LiveTest' }}
annotate tests with: @Category(LiveTest.class)