Log.d(“Gradle”,”Hello World!!!”) welcome to this amazing second half of my best practice tips for gradle build system. You never have to wait for long to successfully build your android projects. In my previous article I shared few tips on gradle best practices. Today, I am dropping the concluding and most interesting part.
- Use static build config values with your debug build: Always use hard-coded values for properties that go in the manifest file or resource files for your debug build type. If the values in your manifest file or your app resources need to update with every build, then Instant Run cannot perform a code swap — it must build and install a new APK. For instance, using dynamic version codes, version names, resources, or any other build logic that alters the manifest file requires a full APK build each time you want to run a change — although the actual change might otherwise require only a hot swap. If your build config requires such dynamic properties, then isolate them to your release build variants and keep the values static for your debug builds, as shown in the
build.gradle
file below.
int MILLIS_IN_MINUTE = 1000 * 60 int minutesSinceEpoch = System.currentTimeMillis() / MILLIS_IN_MINUTE android { ... defaultConfig { // Making either of these two values dynamic in the defaultConfig will // require a full APK build and reinstallation because the AndroidManifest.xml // must be updated (which is not supported by Instant Run). versionCode 1 versionName "1.0" ... } // The defaultConfig values above are fixed, so your incremental builds don't // need to rebuild the manifest (and therefore the whole APK, slowing build times). // But for release builds, it's okay. So the following script iterates through // all the known variants, finds those that are "release" build types, and // changes those properties to something dynamic. applicationVariants.all { variant -> if (variant.buildType.name == "release") { variant.mergedFlavor.versionCode = minutesSinceEpoch; variant.mergedFlavor.versionName = minutesSinceEpoch + "-" + variant.flavorName; } } }
- Use static dependency versions: When you declare dependencies in your
build.gradle
files, you should avoid using version numbers with a plus sign at the end, such as'com.android.tools.build:gradle:2.+'
. Using dynamic version numbers can cause unexpected version updates, difficulty resolving version differences, and slower builds caused by Gradle checking for updates. You should use static/hard-coded version numbers instead. - Enable offline mode: If you are on a slow network connection, your build times may suffer when Gradle attempts to use network resources to resolve dependencies. You can tell Gradle to avoid using network resources by using only the artifacts that it has cached locally.
To use Gradle offline when building with Android Studio, proceed as follows:
- Open the Preferences window by clicking File > Settings (on Mac, Android Studio > Preferences).
- In the left pane, click Build, Execution, Deployment > Gradle.
- Check the Offline work checkbox.
- Click Apply or OK.
Note: If you’re building from the command line, pass the --offline
option.
- Enable configuration on demand: For Gradle to know specifically how to build your app, the build system configures all modules in your project, and their dependencies, before every build (even if you are building and testing only a single module). This slows down the build process for large multi-module projects. To tell Gradle to configure only the modules that you want to build, enable configuration on demand by following these steps:
- Open the Preferences window by clicking File > Settings (on Mac, Android Studio > Preferences).
- In the left pane, click Build, Execution, Deployment > Compiler.
- Check the Configure on demand checkbox.
- Click Apply or OK.
Note:
Gradle 4.6 users: If you’re using either Android Plugin for Gradle 3.0.1 or 3.1.0 with Gradle 4.6, you should disable configuration on demand to avoid some unpredictable build errors. This issue should be fixed in a future version of the plugin.
- Create library modules: Look for code in your app that you can convert into an Android library module. Modularizing your code this way allows the build system to compile only the modules you modify and cache those outputs for future builds. It also makes configuration on demand and parallel project execution more effective (when you enable those features).
- Convert images to WebP: WebP is an image file format that provides lossy compression (like JPEG) as well as transparency (like PNG) but can provide better compression than either JPEG or PNG. Reducing image file sizes, without having to perform build-time compression, can speed up your builds, especially if your app uses a lot of image resources. However, you may notice a small increase in device CPU usage while decompressing WebP images. Using Android Studio, you can easily convert your images to WebP.
- Disable PNG crunching: If you can’t (or don’t want to) convert your PNG images to WebP, you can still speed up your build by disabling automatic image compression every time you build your app. If you’re using Android plugin 3.0.0 or higher, PNG crunching is disabled by default for only the “debug” build type. To disable this optimization for other build types, add the following to your
build.gradle
file:
android { buildTypes { release { // Disables PNG crunching for the release build type. crunchPngs false } } // If you're using an older version of the plugin, use the // following: // aaptOptions { // cruncherEnabled false // } }
Because build types or product flavors don’t define this property, you need to manually set this property to true
when building the release version of your app.
- Enable Instant Run: Instant Run significantly reduces the time it takes to update your app by pushing certain code and resource changes without building a new APK — and, in some cases, without even restarting the current activity. Use Instant Run by clicking Apply Changes after making changes to your app, and it’s enabled by default when you do the following:
>> Build your app using a debug build variant.
>> Use Android plugin for Gradle version 2.3.0 or higher.
>> Set minSdkVersion
to 15 or higher in your app’s module-level build.gradle
file.
>> Deploy your app to a device running Android 5.0 (API level 21) and higher by clicking Run
If you don’t see the Apply Changes button in the toolbar after meeting these requirements, make sure that Instant Run isn’t disabled in the IDE settings by following these steps:
- Open the Settings or Preferences dialog.
- Navigate to Build, Execution, Deployment > Instant Run.
- Make sure Enable Instant Run is checked.
B. Profile your build
Larger projects, or those that implement a lot of custom build logic, may require you to take a deeper look into the build process to find bottlenecks. You can do that by profiling how long Gradle takes to execute each phase of the build lifecycle and each build task. For example, if your build profile shows that Gradle is spending too much time configuring your project, it may suggest that you need to move custom build logic out of the configuration phase. Additionally, if the mergeDevDebugResources
task consumes a large amount of the build time, it may indicate that you need to either convert your images to WebP or disable PNG crunching.
Using profiling to improve your build speed typically involves running your build with profiling enabled, making some tweaks to your build configuration, and profiling some more to observe the results of your changes.
To generate and view a build profile, perform the following steps:
- With your project open in Android Studio, select View > Tool Windows > Terminal to open a command line at the root of your project.
- Perform a clean build by entering the following command. As you profile your build, you should perform a clean build between each build you profile because Gradle skips tasks when inputs to a task (such as source code) don’t change. Thus, a second build with no input changes always runs faster because tasks are not being re-run. So running the
clean
task between your builds ensures that you profile the full build process.
// On Mac or Linux, run the Gradle wrapper using "./gradlew". gradlew clean
3. Execute a debug build of one of your product flavors, such as the “dev” flavor, with the following flags:
gradlew --profile --recompile-scripts --offline --rerun-tasks assembleFlavorDebug
4. After the build completes, use the Projectwindow navigate to the project-root/build/reports/profile/
directory (as shown in figure 1).
5. Right-click the profile-timestamp.html
file and select Open in Browser > Default. The report should look similar to the one shown in figure below. You can inspect each tab in the report to learn about your build, such as the Task Execution tab which shows how long Gradle took to execute each build task.
Here is my final tip:
For a more robust profiling tool, consider using Gradle’s open-source profiler
Cool bananas!!! I have come to the end of my tips on gradle build system.
Finally, I leave you with this !!!
Our greatest weakness lies in giving up. The most certain way to succeed is always to try just one more time.” ―Thomas Edison
Don’t give up, try one more time!!!
No Comment! Be the first one.