Understanding how Gradle works with Android
Module?
Android Studio is build on IntelliJ IDEA which supports module-based project structure. There is new keyword called "Module" in Android Studio. Intellij defines module as:
Module is a separate logical part of a project that incorporates your working sources, libraries, reference to target Java SDK, etc. It can be compiled, run or debugged as a standalone entity.
Project structure
When you make a Android project through Android Studio. Gradle script will be generated automatically. Gradle related files are located like this:
Project ├── settings.gradle ├── build.gradle ├── app │ └── build.gradle ├── libraries │ └── lib1 │ └── build.gradle │ └── lib2 │ └── build.gradle │ ├── gradle │ └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties └── gradle.properties ~/.gradle/gradle.properties
gradle.properties?
gradle.properties
is a Gradle settings in project folder and ~/.gradle/gradle.properties
is a Gradle settings in Gradle user home.
You can set password or gradle settings in both files, but gradle.properties in project folder will be shared with your collaborators.
mavenUser=admin mavenPassword=admin123
org.gradle.jvmargs=-Xmx8192m -XX:MaxPermSize=2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 org.gradle.parallel=true org.gradle.daemon=true
setting.gradle?
To define a multi-project build, you need to create a settings file. The settings file lives in the root directory of the source tree, and specifies which projects to include in the build. It must be called settings.gradle. For this example, we are using a simple hierarchical layout.
Project ├── settings.gradle ├── app └── libraries └── lib1 └── lib2
settings.gradle
include "app" include "libraries:lib1" include "libraries:lib2"
Top-level build.gradle?
Top-level build file where you can add configuration options common to all sub-projects/modules
build.gradle for each module?
Build file for each module
In most cases, you only need to edit the build files at the module level
build.gradle structure?
// This adds Android-specific build tasks to the top-level build tasks and makes the android {...} element available to specify Android-specific build options. apply plugin: 'com.android.application' // configures all the Android-specific build options android { // the compilation target compileSdkVersion 19 // what version of the build tools to use buildToolsVersion "19.0.0" // element configures core settings and entries in the manifest file defaultConfig { minSdkVersion 8 targetSdkVersion 19 versionCode 1 versionName "1.0" } // how to build and package your app. By default, the build system defines two build types: debug and release buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } // the dependencies for this module dependencies { // Module dependency compile project(":lib") // Remote binary dependency compile 'com.android.support:appcompat-v7:19.0.1' // Local binary dependency compile fileTree(dir: 'libs', include: ['*.jar']) }
Integrating open sources
Common Integration Rule
compile 'groupId:artifactId:version'
Android Support Packages
// Google Play Services compile 'com.google.android.gms:play-services:7.3.+' // Support Libraries compile 'com.android.support:appcompat-v7:22.+' compile 'com.android.support:cardview-v7:22.+' compile 'com.android.support:gridlayout-v7:22.+' compile 'com.android.support:leanback-v17:22.+' compile 'com.android.support:mediarouter-v7:22.+' compile 'com.android.support:palette-v7:22.+' compile 'com.android.support:recyclerview-v7:22.+' compile 'com.android.support:support-annotations:22.+' compile 'com.android.support:support-v13:22.+' compile 'com.android.support:support-v4:22.+'
You can find latest Android support package version from here
Realm
compile 'io.realm:realm-android:0.80.+'
You can find more ways to integrating Realm from here
Dynamic Versions
Gradle follows Ivy's version-matchers
Exact Revision Matcher
Revision | Matches |
---|---|
1.0.0 | '1.0.0' |
Sub Revision Matcher
Revision | Matches |
---|---|
1.0.+ | all revisions starting with '1.0.', like 1.0.1, 1.0.5, 1.0.a |
1.1+ | all revisions starting with '1.1', like 1.1, 1.1.5, but also 1.10, 1.11 |
Latest (Status) Matcher
Revision | Matches |
---|---|
latest.integration | all versions |
latest.milestone | all modules having at least 'milestone' as status |
latest.release | all modules having at least 'release' as status |
latest.[any status] | all modules having at least the specified status |
Version Range Matcher
Revision | Matches |
---|---|
[1.0,2.0] | all versions greater or equal to 1.0 and lower or equal to 2.0 |
[1.0,2.0[ | all versions greater or equal to 1.0 and lower than 2.0 |
]1.0,2.0] | all versions greater than 1.0 and lower or equal to 2.0 |
]1.0,2.0[ | all versions greater than 1.0 and lower than 2.0 |
[1.0,) | all versions greater or equal to 1.0 |
]1.0,) | all versions greater than 1.0 |
(,2.0] | all versions lower or equal to 2.0 |
(,2.0[ | all versions lower than 2.0 |
By default, Gradle caches dynamic versions for 24 hours
You can find more about dynamic versions and changing modules from here
Customisation Gradle Settings
Multiple Java Folders & Resource Folders
You can create multiple Java folders and multiple resource folders. It is very useful if you want to manage different type of sources or resources in different folders.
// module build.gradle android { sourceSets { main { java.srcDirs = ['src/main/java', 'src/main/java-realm'] res.srcDirs = ['src/main/res', 'src/main/res-icons', 'src/main/res-mipmaps'] } } }
Basic Customization
You can create your own groovy method and customize build setting with your method.
// module build.gradle def getVersionCode() { def code = ... return code } android { defaultConfig { versionCode getVersionCode() versionName "1.0" minSdkVersion 15 targetSdkVersion 22 } }
Build Type Configurations
You can set custom build types in gradle such as 'beta' and if you build your project in 'beta' version, Gradle will automatically add 'src/beta' folder for building it. You can set API keys for each build types. You can also make different signing configurations for each build type or you can use other build types signing configurations. You can make debuggable release version simply by setting gradle options.
// module build.gradle android { signingConfigs { debug { storeFile file("debug.keystore") storePassword "android" keyAlias "androiddebugkey" keyPassword "android" } release { storeFile file("release.keystore") } } buildTypes { beta { versionNameSuffix "-BETA" applicationIdSuffix ".beta" signingConfig signingConfigs.debug } debug { versionNameSuffix "-DEBUG" applicationIdSuffix ".debug" } debugRelease { debuggable true versionNameSuffix "-DEBUG-RELEASE" applicationIdSuffix ".debug.release" signingConfig signingConfigs.debug } release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } sourceSets.debugRelease.setRoot('src/main') }
Source Folders
Project └── app ├── src │ └── main │ └── beta │ └── debug │ └── release └── build.gradle └── proguard-rules.pro
Codes in each build type folder will be compiled automatically for each build type. (i.e. if current buid type is release, the codes in app/src/release folder will be compiled with codes in app/src/main)
Build Type Dependencies
You can use different compile options for each build types.
android { ... } dependencies { // We are updating Realm and testing newly-released version of Realm. compile 'io.realm:realm-android:0.80.3' betaCompile 'io.realm:realm-android:0.80.3' debugCompile 'io.realm:realm-android:0.80.3' releaseCompile 'io.realm:realm-android:0.80.0' // We are using robolectric for testing projects instrumentTestCompile "org.robolectric:robolectric:3.0" }
Product Flavors
A product flavor defines a customized version of the application build by the project. A single project can have different flavors which change the generated application.
Build Variants
In fact, the output of a project can only be the cross product of the Build Type and, if applicable, the Product Flavor. This is call a build variant. You can set your build variant for each module in Android Studio. There is a button to open build variant window on the left side of Android Studio.
Product Flavor Groups
In some case it is useful to be able to have several dimensions of flavors such as 'abi' and 'version'
android { flavorGroups 'version', 'abi' productFlavors { free { flavorGroup 'version' } paid { flavorGroup 'version' } arm { flavorGroup 'abi' } x86 { flavorGroup 'abi' } mips { flavorGroup 'abi' } } }
There is two flavorGroups ('version', 'abi') and 'version' has 2 productFlavors and 'abi' has 3 productFlavors. Assume we have 2 kinds of build types ('debug', 'release'). We will have 2 ('version') * 3 ('abi') * 2 ('build types') = 12 kinds of build variants.
debug | release | ||
---|---|---|---|
free | arm | free-arm-debug | free-arm-release |
free | x86 | free-x86-debug | free-x86-release |
free | mips | free-mips-debug | free-mips-release |
paid | mips | paid-arm-debug | paid-arm-release |
paid | x86 | paid-x86-debug | paid-x86-release |
paid | mips | paid-mips-debug | paid-mips-release |
Combining sources
Assume we are building a application with 'debug' build type and 'mips' as 'abi' productFlavors and 'free' as 'version' productFlavors.
Source code
Combine all source codes in each folders to build
src/debug/java src/free/java src/mips/java src/main/java
Resources
Overriding mechanisms
src/debug/res (top) src/free/res src/mips/res src/main/res (base)
Signing configuration
Priority Order
android.buildTypes.debug.signingConfig (top) android.productFlavors.free.signingConfig android.productFlavors.mips.signingConfig android.defaultConfig.signingConfig (base)
Package Name
Overriding mechanisms + Suffix
android.productFlavors.free.packageName (top) android.productFlavors.mips.packageName android.defaultConfig.packageName src/main/AndroidMenifest.xml (base) + android.buildTypes.debug.applicationIdSuffix
Testing
Source Sets
src/androidTest src/androidTestFree src/androidTestMips
Dependencies
dependencies { androidTestCompile "org.robolectric:robolectric:3.0" androidTestFreeCompile "org.robolectric:robolectric:3.0" androidTestMipsCompile "org.robolectric:robolectric:3.0" }
Using Java 7
With Android KitKat (buildToolsVersion 19) you can use the diamond operator, multi-catch, strings in switches, try with resources, etc. To do this, add the following to your build file:
android { compileOptions { sourceCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_7 } }
Author
Name : Leonardo Taehwan Kim Email : contact@thefinestartist.com Website : http://www.thefinestartist.com
Tested Version
Android Studio: 1.2.11 Gradle: 1.2.2