Switching from Ant to Gradle
Wednesday, October 8, 2014For a long time, Android projects used Ant. You had a build.xml file, a local.properties file, a project.properties file. You ran ant debug or ant release. It worked.
Then Google announced Gradle as the new build system at I/O 2013. Android Studio is the new IDE replacing Eclipse. Everything is moving at once.
What is wrong with Ant
Ant is fine for simple apps. But once you need more, it becomes painful.
Want two variants of your app, one free and one paid? Good luck. You need separate source folders, separate manifest files, separate build targets. Alot of copy paste.
Want to run some custom Java code during the build? Write an Ant task. Then debug it. Then debug it more.
Dependency management is separate. Most people use Maven for that and have jars checked into the repository. Hundreds of megabytes of jars in git.
<!-- This is how you configure signing in Ant. Not fun. -->
<target name="release" depends="-set-release-mode, -release-obfuscation-check">
<echo>Packaging release build</echo>
</target>
First look at Gradle
The first build.gradle I see looks like this:
apply plugin: 'com.android.application'
android {
compileSdkVersion 21
buildToolsVersion "21.1.1"
defaultConfig {
applicationId "com.example.myapp"
minSdkVersion 14
targetSdkVersion 21
versionCode 1
versionName "1.0"
}
}
dependencies {
compile 'com.android.support:appcompat-v7:21.0.0'
}
This is already better. No XML build targets. Dependency declared in one line with a version. But I don't understand the Groovy DSL. apply plugin? defaultConfig? What is compileSdkVersion vs targetSdkVersion?
I spend probably a week confused.
Build variants
This is where Gradle wins me over completely.
android {
buildTypes {
debug {
applicationIdSuffix ".debug"
debuggable true
}
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
productFlavors {
free {
applicationId "com.example.myapp.free"
}
paid {
applicationId "com.example.myapp"
}
}
}
Free debug, free release, paid debug, paid release. All from one file. Different app ids so both versions can be installed on the same device. This would have been a nightmare in Ant.
The migration
We do ours over a weekend. The main steps:
- Import the project into Android Studio. It migrates the structure automatically
- Move source from
src/tosrc/main/java/ - Move resources from
res/tosrc/main/res/ - Move manifest to
src/main/ - Replace
build.xmlwithbuild.gradle - Replace jar files in
libs/with proper dependency declarations
Step 6 is the satisfying part. Delete 300MB of jars, replace with 20 lines of dependencies. The first ./gradlew assembleDebug downloads everything from Maven Central automatically.
What is confusing
Gradle itself is a general build tool, not specific to Android. The Android plugin sits on top of it. This means the documentation is split. Some things are Gradle docs, some things are Android Gradle Plugin docs. Hard to know where to look.
Also the incremental builds are slow. Gradle has a daemon that helps a lot but the first time you run a build is always painful.
./gradlew assembleDebug
BUILD SUCCESSFUL in 2m 14s
2 minutes for a small app. Ant is faster. The daemon will improve things but right now, every cold build is a coffee break.
The error messages are sometimes useless too. Something went wrong in your build.gradle and Gradle just says "build failed" with a stack trace that points to Groovy internals. You learn to read those eventually.
Build variants alone justify the migration. The dependency management is so much cleaner. CI becomes simpler. Just run ./gradlew assembleRelease and you get the signed APK.
It is worth the pain.