avatarMaxi Rosson

Summary

The web content provides a detailed guide on how to stop using the Android Jetifier tool to improve build speeds by fully migrating to AndroidX libraries.

Abstract

The article titled "Say bye-bye to Android Jetifier" outlines a six-step process for Android developers to transition away from using Jetifier, a tool that helps migrate third-party dependencies to use AndroidX. The process begins with migrating the developer's own source code to AndroidX, followed by identifying and handling all support-library-dependent dependencies, including transitive ones. The guide suggests using the "Bye Bye Jetifier" Gradle plugin to detect legacy support library usage and provides strategies for dealing with dependencies that have not been migrated to AndroidX, such as using a standalone Jetifier tool or forking and migrating the library yourself. The article emphasizes the importance of thorough testing after migration and recommends integrating the verification process into the CI pipeline to prevent reintroduction of support-library-dependent libraries.

Opinions

  • The author believes that disabling Jetifier can significantly reduce build times, which is beneficial for Android project development.
  • The author suggests that simply checking the dependencies graph for legacy support libraries is insufficient; a more thorough inspection of the actual code within JAR/AAR files is necessary.
  • The author provides a pragmatic approach to handling dependencies that are not yet migrated to AndroidX, offering multiple solutions depending on the developer's relationship to the library's source code.
  • The author advocates for the use of dependency substitution rules and constraints in Gradle to manage transitive dependencies and ensure the use of AndroidX-compatible versions.
  • The author encourages community contribution by suggesting that developers should send pull requests to maintainers of public libraries to help with the AndroidX migration.
  • The author recommends that developers support the work by contributing via Bitcoin Lightning or PayPal through Ko-fi, indicating a preference for community support over traditional funding models.

Say bye-bye to Android Jetifier

6 steps to stop using Jetifier and reduce your build speed

Jetpack is a set of libraries, tools, and guidance to help you write high-quality apps more easily. Jetpack makes coding easier through best practices, limiting boilerplate code, and simplifying complex tasks. All with the goal of enabling you to focus on the code that you really care about.

AndroidX is the package name for all the libraries within Jetpack. Think of AndroidX as the open-source project used to develop, test, version, and release Jetpack libraries.

Back at I/O 2018, Google announced that Support Library would be refactored into the AndroidX namespace, which was completed with Support Library 28 and the announcement of AndroidX 1.0.

Jetifier helps migrate third-party dependencies to use AndroidX. Jetifier will change the byte code of those dependencies to make them compatible with projects using AndroidX.

Having Jetifier enabled on your project (android.enableJetifier = true on your gradle.properties) impacts on the build speed, because the Android Gradle Plugin has to transform all the support-library-dependent artifacts to AndroidX. So, disabling jetifier is a good idea for your android project if you want to reduce the build speed. But doing that is not always a trivial task. That’s why we prepared a list of 6 steps to follow, so you can fully migrate your app to AndroidX and then safely disable Jetifier.

Step 1

If your own source code is already migrated to androidx, just skip this step and go directly to step 2. If not, migrating your code to androidx should be your first task. You can read this article with some tips & tricks:

Step 2

Get a list of all the support-library-dependent dependencies in your project. This list should also include transitive dependencies.

To do that you can use our Bye Bye Jetifier Gradle plugin:

The plugin verifies on each dependency JAR/AAR (and its transitives) if:

  • any class is using a support library import
  • any layout is referencing a support library class
  • the Android Manifest is referencing a support library class

It also verifies if any support library dependency is resolved on the project.

Why should I use this plugin instead of can-i-drop-jetifier?

The can-i-drop-jetifier plugin only checks for legacy support libraries on the dependencies graph. That’s not enough to decide if you can drop Jetifier. Lots of libraries don’t properly declare on their POMs the legacy support libraries they use as transitive dependencies. So, for those cases, can-i-drop-jetifier says that you can disable Jetifier. But, if you do that, then you are going to have runtime errors when the logic using the legacy support library is executed.Bye bye Jetifier inspects each JAR/AAR, searching for legacy support libraries usages, so it will find more libraries than can-i-drop-jetifier, and you will avoid those runtime errors.

The setup is easy. Just add this configuration to your root build.gradle, replacing X.Y.Z with the latest version

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("com.dipien:bye-bye-jetifier:X.Y.Z")
    }
}

apply plugin: "com.dipien.byebyejetifier"

And then execute the following task:

./gradlew canISayByeByeJetifier -Pandroid.enableJetifier=false

If you have any legacy android support library usage, the task will fail and print a report with all the details.

Example output:

========================================
Project: app
========================================

Scanning com.github.bumptech.glide:glide:3.8.0
 Absolute path: ~/.gradle/caches/modules-2/files-2.1/com.github.bumptech.glide/glide/3.8.0/9bada6526fe0/glide-3.8.0.jar
 Graphs to this dependency:
 +---com.github.bumptech.glide:glide:3.8.0
 Issues found:
 * com/bumptech/glide/Glide.class -> android/support/v4/app/FragmentActivity
 * com/bumptech/glide/Glide.class -> android/support/v4/app/Fragment
 * com/bumptech/glide/manager/RequestManagerRetriever.class -> android/support/v4/app/FragmentManager
 * com/bumptech/glide/manager/RequestManagerRetriever.class -> android/support/v4/app/FragmentActivity
 * com/bumptech/glide/manager/RequestManagerRetriever.class -> android/support/v4/app/Fragment
 * com/bumptech/glide/manager/RequestManagerRetriever.class -> android/support/v4/app/FragmentTransaction
 * com/bumptech/glide/manager/SupportRequestManagerFragment.class -> android/support/v4/app/Fragment
 * com/bumptech/glide/manager/SupportRequestManagerFragment.class -> android/support/v4/app/FragmentActivity
 * com/bumptech/glide/manager/SupportRequestManagerFragment.class -> android/support/v4/app/FragmentManager

Explicit declarations of legacy support dependencies on this project:
 * android.arch.core:common:1.1.1
 * android.arch.lifecycle:common:1.1.0

> Task :canISayByeByeJetifier FAILED

Step 3

For each support-library-dependent library obtained in the previous step, you need to define how to remove all the support library references.

Upgrading the dependency to the latest version should be your first action. If you have luck, it is now migrated to androidx. If not, here are some tips according to the kind of dependency.

For libraries which you are the owner of the source code:

Just migrate it to androidx, upgrade all its dependencies and then release a new version. Remember to add this line to the gradle.properties of your library:

android.useAndroidX = true

That line is especially important if you are using databinding, because it will automatically switch from support library databinding to androidx databinding.

For libraries which you are NOT the owner of the source code:

These are some alternatives:

1. If you don’t have access to the library source code or if its usage is deprecated on your project, you can use the jetifier-standalone command-line tool to transform the library AAR/JAR to a jetified AAR/JAR. This tool executes the same transformation as the Android Gradle Plugin when you have the flag android.enableJetifier enabled

The command to run is simple:

./jetifier-standalone -i <source-library> -o <output-library>

On the Jetifier docs you can find more info about the tool.

Once you generated the jetified AAR/JAR, you should deploy it on any Maven repository using your own groupId and change the artifact coordinates on your project.

This approach is useful if you don’t have access to the library source code or if its usage is deprecated on your project.

2. If the library repo is public but abandoned, you can fork it, migrate the code to androidx and release a new version with a different groupId. This option is useful if you plan to add changes to the source code in the future.

3. If the library repo is public and not abandoned, you can clone it, migrate it to androidx and send a pull request to the maintainer. This approach can take more time, but it is useful if you plan to continue using the library and its new versions in the future.

Tip 1

If the dependency you are replacing by a jetified version is a transitive dependency, then you can define Dependency substitution rules on Gradle, so the old dependency is replaced by the new dependency when resolved.

For example, suppose that com.parse.bolts:bolts-applinks:1.4.0 uses android support, and you migrate/transform to com.sample:bolts-applinks:1.4.0. With the following configuration, you will replace all the original artifact usages:

// Replace artifacts with android support with the jetifier version
allprojects {
  configurations.all {
    resolutionStrategy.dependencySubstitution {
      substitute(module("com.parse.bolts:bolts-applinks:1.4.0")).using(module("com.sample:bolts-applinks:1.4.0")) 
    }
  }
}

Tip 2

If you need to force the upgrade of a transitive dependency, you can add a dependency constraint.

For example, suppose that com.sample:lib:1.0.0 defines com.transitive:lib:1.0.0 as transitive, but this version uses android support. You can force to use com.transitive:lib:2.0.0, which is migrated to androidx

api("com.sample:lib:1.0.0") // 
constraints {
   implementation("com.transitive:lib:2.0.0") {
      because("previous versions use android support")
   }
}

Step 4

You need to verify that your own code and all your dependencies (including transitives) are not support-library-dependent any more.

If you execute the following command:

./gradlew canISayByeByeJetifier -Pandroid.enableJetifier=false

and you get a BUILD SUCCESSFUL with this message:

====================================================================
* No dependencies with legacy android support usages! You can say Bye Bye Jetifier. *
====================================================================
BUILD SUCCESSFUL in 5s
1 actionable task: 1 executed

it means that you achieved that.

Now you can remove theandroid.enableJetifier flag from your gradle.properties.

Step 5

Run your app and test it to be sure that all is working as expected.

Step 6

Once you have disabled Jetifier, you don’t want to add a new support-library-dependent library by mistake when adding/upgrading a dependency on your project. To avoid that kind of issue, you can run thecanISayByeByeJetifier task on your CI tool as part of the PR checks.

Our recommendation is to disable the Bye Bye Jetifier plugin on your local environment and run the verification task on your CI tool: on each PR and your default branches. The following article could help you to configure that:

Follow us for more productivity tools & ideas for Android, Kotlin & Gradle projects.

Support Us

There are different ways to support our work:

  • With Bitcoin Lightning using Alby:
  • With PayPal or a credit card using Ko-fi.

Related Articles

If you enjoyed this article, you might get value out of these ones as well!

Android
Android App Development
Jetifier
Migrate To Androidx
Androidx
Recommended from ReadMedium