$30 off During Our Annual Pro Sale. View Details »

Building Android Apps with Gradle

Building Android Apps with Gradle

See some of the features of the Android plugin for Gradle in action.

Prateek Srivastava

December 04, 2013
Tweet

More Decks by Prateek Srivastava

Other Decks in Programming

Transcript

  1. Building Android Apps
    with Gradle

    View Slide

  2. Gradle
    • Build automation tool, builds upon Maven and
    Ant
    • Uses build.gradle files for configuration
    !
    PROTIP
    • Use the gradle wrapper
    http://www.gradle.org/

    View Slide

  3. Gradle android plugin
    Build with `./gradlew clean assemble`
    !
    Android Tasks
    • assemble
    • clean
    • connectedCheck
    • deviceCheck
    • check
    • build
    !
    ./gradlew tasks --all
    http://tools.android.com/
    tech-docs/new-build-system/
    user-guide

    View Slide

  4. Basic App Structure
    Project
    ├── app
    │ ├── build.gradle
    │ ├── keystore
    │ ├── libs
    │ │ └── *.jar
    │ └── src
    └── build.gradle

    View Slide

  5. Top level build file
    Project
    ├── app
    │ ├── build.gradle
    │ ├── keystore
    │ ├── libs
    │ │ └── *.jar
    │ └── src
    └── build.gradle
    Add configuration
    options common to all
    sub-projects/modules.
    !
    task wrapper(type: Wrapper) {
    gradleVersion = '1.8'
    }

    View Slide

  6. Module build file
    Main application build
    file. It would contain
    information such as
    dependencies, plugins,
    etc.
    With the Android plugin,
    you can define
    additional properties for
    your application, such
    as package name,
    version code, etc.
    Project
    ├── app
    │ ├── build.gradle
    │ ├── keystore
    │ ├── libs
    │ │ └── *.jar
    │ └── src
    └── build.gradle

    View Slide

  7. Sample build.gradle for
    an Android app
    https://github.com/f2prateek/android-device-frame-
    generator/blob/master/app/build.gradle

    View Slide

  8. Basic App Structure
    My build.gradle is
    configured to pick up all jars
    in this folder. Use this for
    dependencies not available
    via published repositories.
    !
    compile fileTree(dir: 'libs', include: '*.jar')
    .
    ├── app
    │ ├── build.gradle
    │ ├── keystore
    │ ├── libs
    │ │ └── *.jar
    │ └── src
    └── build.gradle

    View Slide

  9. Sources
    Project
    ├── app
    │ ├── build.gradle
    │ ├── keystore
    │ ├── libs
    │ │ └── *.jar
    │ └── src
    └── build.gradle

    View Slide

  10. Sources
    │ └── src
    │ ├── debug
    │ │ └── AndroidManifest.xml
    │ ├── instrumentTest
    │ │ ├── AndroidManifest.xml
    │ │ └── java
    │ ├── main
    │ │ ├── AndroidManifest.xml
    │ │ ├── java
    │ │ └── res
    │ └── release
    │ ├── AndroidManifest.xml
    │ └── res
    │ └── values
    │ └── analytics.xml

    View Slide

  11. Main Source Set
    │ └── src
    │ ├── debug
    │ │ └── AndroidManifest.xml
    │ ├── instrumentTest
    │ │ ├── AndroidManifest.xml
    │ │ └── java
    │ ├── main
    │ │ ├── AndroidManifest.xml
    │ │ ├── java
    │ │ └── res
    │ └── release
    │ ├── AndroidManifest.xml
    │ └── res
    │ └── values
    │ └── analytics.xml
    The default source set.
    Stick to this if you want
    no build customization.

    View Slide

  12. Instrument Tests Source Sets
    │ └── src
    │ ├── debug
    │ │ └── AndroidManifest.xml
    │ ├── instrumentTest
    │ │ ├── AndroidManifest.xml
    │ │ └── java
    │ ├── main
    │ │ ├── AndroidManifest.xml
    │ │ ├── java
    │ │ └── res
    │ └── release
    │ ├── AndroidManifest.xml
    │ └── res
    │ └── values
    │ └── analytics.xml

    View Slide

  13. Build Types
    │ └── src
    │ ├── debug
    │ │ └── AndroidManifest.xml
    │ ├── instrumentTest
    │ │ ├── AndroidManifest.xml
    │ │ └── java
    │ ├── main
    │ │ ├── AndroidManifest.xml
    │ │ ├── java
    │ │ └── res
    │ └── release
    │ ├── AndroidManifest.xml
    │ └── res
    │ └── values
    │ └── analytics.xml
    The Android plugin
    gives you release and
    debug configurations
    for free. Simply create
    a source folder for
    each configuration
    and get started with
    basic build
    customization.

    View Slide

  14. Build Types
    Some added tasks:
    • assembleDebug
    • assembleRelease
    !
    ./gradlew assembleRelease
    OR
    ./gradlew aR
    Each configuration
    creates some
    appropriate
    corresponding tasks.

    View Slide

  15. Android Configuration
    defaultConfig {

    minSdkVersion 14

    targetSdkVersion 19

    packageName "com.f2prateek.dfg"

    versionCode versionMajor * 10000 + versionMinor * 1000 + versionPatch * 100 + versionBuild

    versionName "${versionMajor}.${versionMinor}.${versionPatch}"

    buildConfig """\

    public static final int VERSION_MAJOR = ${versionMajor}.;

    """

    }
    def versionMajor = 2

    def versionMinor = 0

    def versionPatch = 0

    def versionBuild = 1

    View Slide

  16. Android Configuration
    This sample :
    • Defines minSdkVersion and maxSdkVersion
    • Defines package name
    • Defines version code and version name
    • Adds version name to BuildConfig (access it with
    BuildConfig.VERSION_MAJOR, no need for a
    Context!). Next version of the build tools will have
    more information out of the box, such as package
    name, version name, version code, etc.

    View Slide

  17. Customizing Builds

    debug {

    packageNameSuffix ".debug"

    versionNameSuffix "-debug"

    }

    release {

    signingConfig signingConfigs.release

    }

    View Slide

  18. Customizing Builds
    This sample :
    • Adds a suffix to the package name for debug
    build types
    • Adds a suffix to the version name for debug
    build types
    • Configures release build types to use a
    signing configuration that is shown in the next
    slide

    View Slide

  19. Customizing Builds : Merging
    • All build types share code from the main
    source set
    • The manifest is merged into the app manifest
    • The code acts as just another source folder
    • The resources are overlayed over the main
    resources, replacing existing values

    View Slide

  20. Customizing Builds : Uses
    • Permissions in debug mode only, but not in
    release mode
    • Custom implementation for debugging
    • Different resources for debug mode (for
    instance when a resource value is tied to the
    signing certificate)

    View Slide

  21. Custom Build Types
    beta.initWith(buildTypes.release)

    beta {

    versionNameSuffix "-beta"

    }

    sourceSets.beta.setRoot('src/release')
    This creates a custom build
    type named ‘beta’, initializing
    it from the properties of the
    release build type.
    By default, it would have it’s
    source set under ‘src/beta’.
    Here I manually set the
    source set to be under ‘src/
    release’. The only difference
    between the two versions in
    my case is that beta has a
    suffix in it’s version name.

    View Slide

  22. Signing packages
    signingConfigs {

    release {

    storeFile file("keystore")

    storePassword "notYourRealPassword"

    keyAlias "keystore"

    keyPassword "notYourRealPassword"

    }

    }
    task askForPasswords << {

    def storePassword = new String(System.console().readLine("\n\$ Enter keystore password: "))

    def keyPassword = new String(System.console().readLine("\n\$ Enter key alias password: "))

    android.signingConfigs.release.storePassword = storePassword

    android.signingConfigs.release.keyPassword = keyPassword

    }

    !
    tasks.whenTaskAdded { theTask ->

    if (theTask.name.equals("validateReleaseSigning")) {

    theTask.dependsOn "askForPasswords"

    }

    }

    View Slide

  23. Signing packages
    This uses a file ‘keystore’ with an
    alias ‘keystore’. It asks for a
    password for both via the
    command line. Alternatively, you
    can make it pick up system
    properties, or pick them up in a
    file like signing.properties

    View Slide

  24. Renaming the .apk file
    applicationVariants.all { variant ->

    apk = variant.packageApplication.outputFile;

    newName = apk.name.replace(".apk", "-v${defaultConfig.versionName}-${versionBuild}.apk");

    newName = newName.replace("app", "${defaultConfig.packageName}");

    variant.packageApplication.outputFile = new File(apk.parentFile, newName);

    if (variant.zipAlign) {

    variant.zipAlign.outputFile = new File(apk.parentFile, newName.replace("-unaligned", ""));

    }

    }

    View Slide

  25. Renaming the .apk file
    Produces the following apk’s
    • com.f2prateek.dfg-beta-unaligned-v2.0.0-1.apk

    • com.f2prateek.dfg-beta-v2.0.0-1.apk

    • com.f2prateek.dfg-debug-unaligned-v2.0.0-1.apk

    • com.f2prateek.dfg-release-unaligned-v2.0.0-1.apk

    • com.f2prateek.dfg-release-v2.0.0-1.apk

    View Slide

  26. Checkstyle (thank Jake Wharton!)
    apply plugin: 'checkstyle'

    !
    checkstyle {

    configFile project.file('../checkstyle.xml')

    showViolations true

    }

    !
    android.applicationVariants.all { variant ->

    def name = variant.buildType.name

    def checkstyle = project.tasks.create "checkstyle${name.capitalize()}", Checkstyle

    checkstyle.dependsOn variant.javaCompile

    checkstyle.source variant.javaCompile.source

    checkstyle.classpath = project.fileTree(variant.javaCompile.destinationDir)

    checkstyle.exclude('**/BuildConfig.java')

    checkstyle.exclude('**/R.java')

    project.tasks.getByName("check").dependsOn checkstyle

    }

    View Slide

  27. Checkstyle for library projects
    apply plugin: 'checkstyle'

    !
    checkstyle {

    configFile project.file('../checkstyle.xml')

    showViolations true

    }

    !
    android.libraryVariants.all { variant ->

    def name = variant.buildType.name

    def checkstyle = project.tasks.create "checkstyle${name.capitalize()}", Checkstyle

    checkstyle.dependsOn variant.javaCompile

    checkstyle.source variant.javaCompile.source

    checkstyle.classpath = project.fileTree(variant.javaCompile.destinationDir)

    checkstyle.exclude('**/BuildConfig.java')

    checkstyle.exclude('**/R.java')

    project.tasks.getByName("check").dependsOn checkstyle

    }

    View Slide

  28. Sample of Manifest in
    release, debug and
    main
    https://github.com/f2prateek/
    android-device-frame-generator

    View Slide