Using the new Build System Android 2012. 11. 19. 18:01

http://tools.android.com/tech-docs/new-build-system 
We are working on a new build system to replace both the build system inside ADT and Ant.


Using the new Build System

Using the new Build System

The new build system is based on Gradle.
If you are not familiar with Gradle, it is recommended to read at least the first few chapters ofhttp://gradle.org/docs/current/userguide/userguide_single.html

The location of the SDK folder is still needed and is provided by one of the following methods:
  • local.properties file with a sdk.dir property, similar to the current build system. This is located in the project root directory. In multi-project setup, this is next to settings.gradle.
  • ANDROID_HOME environment variable
All other configuration goes in the standard build.gradle file.

Using the new Android plugin for Gradle

The android plugin for gradle is available through Maven:
  • groupId: com.android.tools.build
  • artifactId: gradle
  • version (current milestone): 0.1
Requirements:
Gradle 1.2.
The Android Platform-Tools component in version 15 rc7. To download it, you will need to enable the preview channel in the SDK Manager. Read more about it here.

To use it in your build.gradle file, put at the top:
buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.1'
    }
}
apply plugin: 'android'

For library project, the plugin to apply is ‘android-library

In the future we will investigate how to simplify this step.

Basic Project Setup

All configuration related to the Android plugin is done inside the android namespace:
android {
    ...
}

The most important setting is the build target (previously found in project.properties):
android {
    target = ‘android-15’
}

Changing the default configuration is done using the defaultConfig object:
android {
    target = ‘android-15’
    defaultConfig {
        versionCode = 12
        versionName = “2.0”
    }
}

Default Config can be configured with the following properties:
  • packageName (String)
  • versionCode (int)
  • versionName (String)
  • minSdkVersion (int)
  • targetSdkVersion (int)
  • testPackageName (String)
  • testInstrumentationRunner (String)
  • signingStoreLocation (String)
  • signingStorePassword (String)
  • signingKeyAlias (String)
  • signingKeyPassword (String)
  • buildConfig (String...)
Note: it is best not to put signing passwords in the build script, and instead have your CI server does the signing itself, or use a local gradle.properties file.
However, you can use these signing properties if you share a single debug keystore across developers.

Build Types and Product Flavors

Creating new build types or editing the built-in debug and release is done with the buildTypes element. This configures the debug build type and adds another one called “staging”:
android {
    buildTypes {
        debug {
            packageNameSuffix = “.debug”
        }
        staging {
            packageNameSuffix = “.staging”
            debuggable = true
            debugSigned = true
        }
    }
}

Build Types can be configured with the following properties:
  • debuggable (bool; default:false; true for debug)
  • debugSigned (bool; default:false; true for debug)
  • debugJniBuild (bool; default:false; true for debug)
  • packageNameSuffix (String; default:null)
  • runProguard (bool; default:false) // unused right now.
  • zipAlign (bool; default:true; false for debug)
  • buildConfig (String...)
Creating product flavors is done with the productFlavors element:
android {
    defaultConfig {
        versionCode = 12
        minSdkVersion = 8
    }
    productFlavors {
        freeapp {
            packageName = “com.example.myapp.free”
            minSdkVersion = 10
        }
        paidapp {
            packageName = “com.example.myapp.paid”
            versionCode = 14
        }
    }
}

Flavors can be configured with the same properties as the default config. If both define a properties, then the flavor overrides the default config.

Flavor Groups

Using multi-flavor variants is done with the following two steps:

  • Defining the flavors groups. The order is important, they are defined higher priority first.
  • Assigning a group to each flavor.
android {
    flavorGroups “abi”, “version”

    productFlavors {
        freeapp {
            group = “version”
            ...
        }
        x86 {
            group = “abi”
            ...
        }
    }
}

Other Options

BuildConfig

BuildConfig is a class that is generated automatically at build time.
Similar to the old build system, the class is generated with a DEBUG boolean field. In this case it maps to the value ofBuildType.debuggable.

On top of this you can now insert new items in the class. This is done by providing full Java lines.
This is possible from the defaultConfig, any flavors, any build types. All lines are aggregated together in the same class for a given variant.

For instance: 
android {
    target = "android-15"

    defaultConfig {
        buildConfig "private final static boolean DEFAULT = true;", \
                "private final static String FOO = \"foo\";"
    }

    buildTypes {
        debug {
            packageNameSuffix = ".debug"
            buildConfig "private final static boolean STAGING = false;"
        }
        staging {
            packageNameSuffix = ".staging"
            buildConfig "private final static boolean STAGING = true;"
        }
        release {
            buildConfig "private final static boolean STAGING = false;"
        }
    }
}

Aapt Options

To provide options to aapt, the aaptOptions element is used. Right now two options are supported (more will come later):
  • noCompress (String list): list of extension to not compress
  • ignoreAssetsPattern: Assets to be ignored. Default pattern is: !.svn:!.git:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*.scc:*~
android {
    target = "android-15"

    aaptOptions {
        ignoreAssetsPattern = “!.svn:!.git:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*.scc:*~”
        noCompress "txt", “foo”
    }
}

Using Library Projects

As mentioned above, the plugin for library projects is android-library. It uses the same Maven artifact.

Libraries don’t have flavors, and only two build types. They can be configured this way:
android {
    target = “android-15”
    debug {
        ...
    }
    release {
        ...
    }
}

Using a library is done one of the following way:
Uploading to a maven repo is done the same way a regular Java library is uploaded. See more information here:http://www.gradle.org/docs/current/userguide/maven_plugin.html

Using a library through a repo is the same as a regular Java library, using the groupIdartifactId and version.

Standard Tasks

Java projects built with Gradle use 4 main tasks:
  • assemble -- assemble the software
  • check -- builds and run the checks and tests
  • build -- runs assemble and check
  • clean
The Android plugin use the same tasks but extends the first two to handle build variants.

For instance, a project with flavor1 and flavor2 and the two default build types will have the following 4 tasks:
  • assembleFlavor1Debug
  • assembleFlavor2Debug
  • assembleFlavor1Release
  • assembleFlavor2Release
On top of these, 4 other assemble tasks are available
  • assembleDebug -- builds all debug variants (for all flavors)
  • assembleRelease -- builds all release variants (for all flavors)
  • assembleFlavor1-- builds all flavor1 variants (for all build types)
  • assembleFlavor2-- builds all flavor2 variants (for all build types)
Adding new flavors and new build types will automatically create new assemble type tasks.

Additionally, assemble tasks for test apps are created:
  • assembleFlavor1Test -- builds the test app for the flavor1 app.
  • assembleFlavor2Test -- builds the test app for the flavor2 app.
  • assembleTest -- builds all test apps.
The default assemble tasks will call all (non test) assemble<flavors><buildtypes> tasks to build all variants of the application.

The check task is augmented similarly:
  • checkFlavor1Debug -- tests the flavor1 variant
  • checkFlavor2Debug -- tests the flavor2 variant
The default check tasks calls all check<flavor> tasks.

Checks are run by doing the following
  1. Install apps (if testing a library, only the test app)
  2. run tests
  3. Uninstall apps
Install / uninstall is done with the following tasks
  • install<flavors><type> for each variant
  • uninstall<flavor><type> for each variant
Additionally uninstallAll attempts to uninstall all variants.

Building an android application takes a lot of steps and each are available to be run on demand.
Here’s a full list of tasks used to build an application:
  • prepare<Variant>Dependencies
  • process<Variant>Manifest
  • generate<Variant>BuildConfig
  • crunch<Variant>Res
  • process<Variant>Res
  • compile<Variant>Aidl
  • compile<Variant>
  • dex<Variant>
  • package<Variant>

Customizing the tasks

Gradle provides an API to query for tasks by name or by classes.

The classes used by the Android tasks are the following:
  • Compile -- java compilation
  • CrunchResourcesTask
  • ProcessManifestTask
  • GenerateBuildConfigTask
  • ProcessResourcesTask
  • CompileAidlTask
  • DexTask
  • PackageApplicationTask
  • ZipAlignTask
In the future we intend to provide a custom API to access flavors, build types, and variants, as well as task inputs/output to do easier manipulation of the tasks.

Working with and Customizing SourceSets

Starting with 0.2, the build system uses its own SourceSet objects intead of the ones provided by the Java plugin.
You can use them to configure the location of all source elements as well as (in the case of the java source and resource folders) customize filters and exclusion.

The default config creates two sourcesets: "main" and "test". All flavors and build types automatically create their own sourceset, named after the flavor/build type name. Additionally, all flavors create a corresponding test flavor named "test<Flavorname>"

Default sourceset location is under src/<sourceset>
Sourceset have the following properties:
  • manifest, type AndroidSourceFile, default location src/<sourceset>/AndroidManifest.xml
  • res, type AndroidSourceDirectory, default location src/<sourceset>/res/
  • assets, type AndroidSourceDirectory, default location src/<sourceset>/assets/
  • aidl, type AndroidSourceDirectory, default location src/<sourceset>/aidl/
  • renderscript, type AndroidSourceDirectory, default location src/<sourceset>/renderscript/
  • jni, type AndroidSourceDirectory, default location src/<sourceset>/jni/
as well as the normal java project sourceset properties:

AndroidSourceFile and AndroidSourceDirectory have a single configurable property, respectively srcFile andsrcDir.

Example of reconfiguring the sourcesets to match an existing project structure:
android {
    sourceSets {
        main {
            manifest {
                srcFile 'AndroidManifest.xml'
            }
            java {
                srcDir 'src'
                exclude 'some/unwanted/package/**'
            }
            res {
                srcDir 'res'
            }
            assets {
                srcDir 'assets'
            }
            resources {
                srcDir 'src'
            }
        }
        test {
            java {
                srcDir 'tests/src'
            }
        }
    }
}

For more information about working with Sourceset, see: http://gradle.org/docs/current/userguide/java_plugin.html#sec:source_sets
Note that for Android projects, the sourceSets container must be modified inside the android container.