Android-SDK-Setup

Install android tooling

Whenever I return to android development after half a year, I need at least one day to get decent versions of all the needed component work nicely together. This time I started from scratch:

  • Set ANDROID_HOME to a empty directory
  • Download the sdk and only the sdk
  • unzip -d $ANDROID_HOME ~/Downloads/sdk-tools-darwin/linux-version.zip
  • In $ANDROID_HOME run tools/bin/sdkmanager --licenses to accept all current licenses
  • In $ANDROID_HOME run tools/bin/sdkmanager --update to bring the tool itself uptodate
    • In $ANDROID_HOME run tools/bin/sdkmanager packagenames to install all needed packages
    • For me: tools/bin/sdkmanager "build-tools;26.0.0" "extras;android;m2repository" "platform-tools" "platforms;android-23" followed by tools/bin/sdkmanager --uninstall emulator results in around 750GB of development tools needed for one of my current apps.
  • Download the newest intellij (I use the jetbrains toolbox) and start a new android project there

To get the best results I use almost always the latest stable versions. Only take rc's, betas, ... if you know exactly what you are doing. Most of the time you have to update them quite soon.

Versioning

As all sources are in git, I suggest to use the following scheme to version android. Keep the versions out of AndroidManifest.xml and put them instead into build.gradle. Manage versionCode manually (or automate this in a release script), generate versionName by git describe --dirty. For git describe to work always, there has to be a tag in the repository. It does not work on a repository without tags.

Minimal snippet of build.gradle to get this working:

...
android {
  defaultConfig {
    versionCode 2
    versionName "git describe --dirty".execute().text.trim();
  }
...
Module structure

I suggest to divide the app into one part purely java and unit test this extensively, and another part that does all the android and ui specific glue code. In the best case this should not be too much on top of the real business logic.

settings.gradle - just pulls in all the modules

include ':lib'
include ':app'

lib/build.gradle - normal java project with 1.7 compatibility

...
sourceCompatibility = 1.7
targetCompatibility = 1.7
...

app/build.gradle This is the most tricky one, I will go through step by step

Android build tools are needed for the buildscript itself (this must be fitting for intellij's and gradle's versions):

...
buildscript {
  repositories {
    jcenter()
    mavenCentral()
  }
  dependencies {
    classpath 'com.android.tools.build:gradle:2.3.3'
  }
}
apply plugin: 'com.android.application'
...

Pull in your libs:

...
dependencies {
  compile ...
  annotationProcessor ...
  compile project(':lib')
}
...

Unit-Testing

Because of the separation it is possible to do a lot of work with normal unit-tests. I did not look into android unit-testing in the last years, but it is supposed to be more evolved than to the android 1.0 time. Still I prefer to test as much as possible with normal junit tests. These are my settings for normal java modules:

...
test {
  testLogging {
    showStandardStreams = true
    exceptionFormat = 'full'
  }
}
apply plugin: 'jacoco'
jacocoTestReport {
  reports {
    html.enabled = true
    xml.enabled = true
    csv.enabled false
  }
}
check.dependsOn jacocoTestReport
...

For android modules I have this in place:

...
android {
  testOptions.unitTests.all {
    testLogging {
    events 'passed', 'skipped', 'failed', 'standardOut', 'standardError'
  }
}
...
Distinguing between debug and release versions

the gradle android build is very sophisticated in producing different flavors and whatnot of the application. For simple application it is important to know, that you can deploy several versions to the target at the same time (e.g. one debug and one release version). To make it more easy to distinguing between them its possible to do adjustments like this in app/build.gradle:

...
android {
  buildTypes {
    release {
      applicationIdSuffix ".release"
      resValue "string", "app_name", "Appname"
    }
    debug {
      applicationIdSuffix ".debug"
      resValue "string", "app_name", "Appname-Debug"
    }
  }
...
Release to play-store

Prerequisites:

  • Various artwork
  • Keystore for signing the apk. I suggest you use the Google Play App Signing. There google creates and keeps a certificate for signing apps that you upload with your upload certificate. In case you loose the upload certificate, you can revoke this and put a new one to google play.

Put the signing into gradle like described on the google page. The only twist I use is to store the password in the keychain/ring:

...
// from http://stackoverflow.com/a/22597752
def passwordFromKeychain = { name ->
  return "security find-generic-password -s ${name} -a ${name} -w".execute().text.trim();
}
android {
  signingConfigs {
    release {
      // just add a new password with appname-play-store, appname-play-store and password in keychain on osx
      storeFile file("store/release.keystore")
      storePassword passwordFromKeychain("appname-play-store")
      keyAlias "appname"
      keyPassword passwordFromKeychain("appname-play-store")
    }
  }
  buildTypes {
    release {
      signingConfig signingConfigs.release
...