Chapter 9. Advanced Build Customization

Now that you know how Gradle works, how to create your own tasks and plugins, how to run tests, and how to set up continuous integration, you can almost call yourself a Gradle expert. This chapter contains a few tips and tricks that we have not mentioned in the previous chapters that make it easier to build, develop, and deploy Android projects using Gradle.

In this chapter, we will cover the following topics:

  • Reducing the APK file size
  • Speeding up builds
  • Ignoring Lint
  • Using Ant from Gradle
  • Advanced app deployment

We will start out by looking at how we can reduce the size of the build output and why that is useful.

Reducing the APK file size

The size of APK files has been increasing dramatically in the last few years. There are several causes for this—more libraries have become available to Android developers, more densities have been added, and apps are getting more functionality in general.

It is a good idea to keep APKs as small as possible. Not only because there is a 50 MB limit on APK files in Google Play, but a smaller APK also means that users can download and install an app faster, and it keeps the memory footprint down.

In this section, we will look at a few properties in the Gradle build configuration file that we can manipulate to shrink APK files.

ProGuard

ProGuard is a Java tool that can not only shrink, but also optimize, obfuscate, and preverify your code at compile time. It goes through all the code paths in your app to find code that is not used and deletes it. ProGuard also renames your classes and fields. This process keeps the footprint of the app down, and makes the code more difficult to reverse engineer.

The Android plugin for Gradle has a Boolean property called minifyEnabled on the build type that you need to set to true to enable ProGuard:

android {
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

When you set minifyEnabled to true, the proguardRelease task is executed and invokes ProGuard during the build process.

It is a good idea to retest your entire application after enabling ProGuard, because it might remove some code that you still need. This is an issue that has made lots of developers weary of ProGuard. To solve this problem, you can define ProGuard rules to exclude certain classes from getting removed or obfuscated. The proguardFiles property is used to define the files that contain ProGuard rules. For example, to keep a class, you can add a simple rule like this:

-keep public class <MyClass>

The getDefaultProguardFile('proguard-android.txt') method fetches the default ProGuard settings from a file called proguard-android.txt, which comes with the Android SDK in the tools/proguard folder. The proguard-rules.pro file gets added to new Android modules by default by Android Studio, so you can simply add rules specific to the module in that file.

Note

The ProGuard rules are different for each app or library you build, so we will not go into too much detail in this book. If you want to know more about ProGuard and ProGuard rules, check the official Android ProGuard documentation at http://developer.android.com/tools/help/proguard.html.

Besides shrinking the Java code, it is also a good idea to shrink the used resources.

Shrinking resources

Gradle and the Android plugin for Gradle can get rid of all unused resources at build time, when the app is being packaged. This can be useful if you have old resources that you forgot to remove. Another use case is when you import a library that has lots of resources, but you only use a small subset of them. You can fix this by enabling resource shrinking. There are two ways to go about shrinking resources, automatic or manual.

Automatic shrinking

The easiest way is to configure the shrinkResources property on your build. If you set this property to true, the Android build tools will automatically try to determine which resources are not used, and not include them in the APK.

There is one requirement for using this feature, though you have to enable ProGuard as well. This is due to the way the resource shrinking works, as the Android build tools cannot figure out which resources are unused until the code that references these resources has been removed.

The following snippet shows how to configure automatic resource shrinking on a certain build type:

android {
    buildTypes {
    release {
            minifyEnabled = true
            shrinkResources = true
        }
    }
}

If you want to see exactly how much smaller your APK becomes after enabling automatic resource shrinking, you can run the shrinkReleaseResources task. This task prints out how much it has reduced the package in size:

:app:shrinkReleaseResources
Removed unused resources: Binary resource data reduced from 433KB to 354KB: Removed 18%

You can get a detailed overview of the resources that are stripped from the APK, by adding the --info flag to your build command:

$ gradlew clean assembleRelease --info

When you use this flag, Gradle prints out a lot of extra information about the build process, including every resource it does not include in the final build output.

One problem with automatic resource shrinking is that it might remove too many resources. Especially resources that are used dynamically might be accidentally stripped out. To prevent this, you can define exceptions in a file called keep.xml that you place in res/raw/. A simple keep.xml file will look like this:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:keep="@layout/keep_me,@layout/also_used_*"/>

The keep.xml file itself will also be stripped out of the final result.

Manual shrinking

A less drastic way to strip out resources is to get rid of certain language files or images for certain densities. Some libraries, such as Google Play Services, include a lot of languages. If your app only supports one or two languages, it does not make sense to include all the language files from these libraries in the final APK. You can use the resConfigs property to configure the resources you want to keep, and then the rest will be thrown out.

If you want to keep only English, Danish, and Dutch strings, you can use resConfigs like this:

android {
    defaultConfig {
        resConfigs "en", "da", "nl"
    }
}

You can do this for density buckets as well, like this:

android {
    defaultConfig {
        resConfigs "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"
    }
}

It is even possible to combine languages and densities. In fact, every type of resource can be restricted using this property.

If you are having a hard time setting up ProGuard, or you just want to get rid of resources for languages or densities your app does not support, then using resConfigs is a good way to get started with resource shrinking.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset