Mark Eschbach

Software Developer && System Analyst

Building Android apps using Gradle

  • ${PROJECT_ROOT}/gradle/wrapper/gradle-wrapper.properties contains the key distributionUrl which embeds the version of Gradle to utilize near the end of the file. The next time the build wrapper is updated the new version will be pulled down.
  • ${PROJECT_ROOT}/build.gradle - Controls the build environment && Anrdoid Gradle Plugin version.
  • ${PROJECT_ROOT}/app/build.gradle - Controls the project specific build.
    • To have duel deployment of both the production application and the an indevelopment version, append a suffix to the target.
      
      android {
          compileSdkVersion 19
          buildToolsVersion "20.0.0"
      
          defaultConfig {
              applicationId "test.android.application"
              minSdkVersion 16
              targetSdkVersion 19
          }
      
          buildTypes {
              debug {
                  applicationIdSuffix ".debug"
              }
              release {
                  runProguard true
                  proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
              }
          }
      }
      
      
    • Automatic signing with Jenkins

      Continous deployment is great, however quickly becomes difficult to do for Android due to the need to sign the application and push it into the Google Play Store. When using Jenkins you can easily allow the system to sign the application and push it up using the Google Play Android Publisher Plugin. The tricky part is getting the APK signed in a configurable way. Sure, you could just hardwire the configuration, however in the case Jenkins goes on strike I like to be able to build production APKs in other ways.

      The following uses a project property to conditionally configure the release for signing. If the project property 'signing.config' is defined then the file pointed to will be loaded for the specified keys.

      
      android {
      	.
      	.
      	.
          signingConfigs {
              release {
                  def singingConfig = project.properties.get("signing.config")
                  if( singingConfig ){
                      logger.info("Using signing override.")
                      Properties config = new Properties()
                      File propertiesFile = new File( singingConfig )
                      propertiesFile.withInputStream {
                          config.load(it)
                      }
      
                      storeFile file(config.keyStore)
                      storePassword config.keyStorePassword
                      keyAlias config.alias
                      keyPassword config.secret
                  }
              }
          }
      	.
      	.
      	.
          buildTypes {
      				...
              release {
      					signingConfig signingConfigs.release
              }
      				...
          }
      }
      

      To ensure your configuration has been properly loaded you can use the follow: gradlew -Psigning.config=/some/path/to/keys.properties signingConfig. If your entires don't look like debug configurations (IE: contianing cryptographic checksums) something has gone wrong and your APKs will not be signed. Otherwise when you run the task assembleRelease the APK should be built into app/build/outputs/*-release.apk.

  • Jenkins build Pipeline

    Ideal the appilcation build pipeline would be as follows for each variant:

    1. Run unit tests for all variants

      The unit tests reports can be picked up by the expression app/build/test-results/**/*.xml.

    2. Build and sign specific variant

      To build and sign the production APK you can simply use assemble${varient}. For example, to build the standard relese version one would use assembleRelease. Unless you have disabled Progaurd, you should probably archieve the mapping files usually contained under app/build/outputs/mapping/${varient}.

      When the above release configuration for Jenkins I would recommend using the goal signingReport to view the keys.

    3. Run automated acceptance tests

      From here you can upload the APK into an emulator or onto an actual device to run automated acceptance tests against. Unforunately at this time I can't get ADB to run against on an SMP linux machine, so I couldn't get my Jenkins configuration to fully work.

    4. Push APK to your target channel

      There was an excellent plugin developed for Jenkins for this. The initial setup is Jenkins wide and only slightly painful when dealing with the Google Developer's Console and the Play Store Console. Once seutp with the proper API keys one could use the glob **/build/outputs/*/*-${varient}.apk to locate the APK to be published.