Say bye-bye to Android Jetifier

6 steps to stop using Jetifier and increase 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.

The setup is easy. Just add this configuration to your root build.gradle:

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

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
* 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/SupportRequestManagerFragment.class -> android/support/v4/app/Fragment

Legacy support dependencies:
* com.android.support:support-annotations:28.0.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 15s
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.



This article contains Affiliate Links. If you purchase anything after clicking an affiliate link, I may receive some compensation.

If you want to learn Android, here you have some recommended books

Comments

Popular Posts

Versioning Android apps

Circle CI + Android configuration tips