AndroidX migration

This is my notes for migrating Android Support Library to AndroidX. I hope this is helpful for people working on the same task.

If you don’t know what AndroidX is, the official doc explains the basics. Since it’s short, I will not repeat it here.



Migration process
The migration tool may not be enough

The happiest path is that running the migration tool from “Refactor” > “Migrate to AndroidX” from the menu completes all the necessary work.

For those of us with more complex gradle setup and a good amount of dependencies to third-party libraries, we may have to manually modify some occurrences.

Manually? :/

If you have your version names defined in a separate file, the tool will overwrite that variable reference with hardcoded version name. So you would need to define version name constants and manually update everywhere to reference that.

Any other places you have the dependency names mentioned in your gradle files, such as under resolutionStrategy, excludes, or etc, you will also need to manually update those accordingly. You can refer to the mapping table.

Third-party library issues

Jetifier should take care of the transitive dependencies, but you may still encounter issues with some libraries. Usually the latest versions of that library by now supports AndroidX (or work is in progress). For instance, you might face issues with certain versions of glide, dagger, butter knife, etc. Visit their github page and read the Releases/Issues for more details.

Jetifier

As mentioned in the official doc, the migration tool automatically writes a couple lines to gradle.properties file.

1
2
android.enableJetifier=true
android.useAndroidX=true

If your project is small and you know you don’t have any transitive dependencies that still use the Support Library, you can set enableJetifier to false. Otherwise, you need it set to true and you will want to periodically analyze your transitive dependencies until there are dependencies to the Support Library.

Quoting the official doc,

android.useAndroidX: When set to true, the Android plugin uses the appropriate AndroidX library instead of a Support Library. The flag is false by default if it is not specified.

android.enableJetifier: When set to true, the Android plugin automatically migrates existing third-party libraries to use AndroidX by rewriting their binaries. The flag is false by default if it is not specified.

There is also a standalone version of jetifier if anyone has needs.

What is useAndroidX for?

What enableJetifier does is clear, but I was wondering why we would need to set useAndroidX. I dug into the gradle plugin’s codebase hosted on Google Git.

I found this interesting comment.

1
2
3
4
5
6
7
8
9
10
11
12
// USE_ANDROID_X indicates that the developers want to be in the AndroidX world, whereas
// ENABLE_JETIFIER indicates that they want to have automatic tool support for converting
// not-yet-migrated dependencies. Developers may want to use AndroidX but disable Jetifier
// for purposes such as debugging. However, disabling AndroidX and enabling Jetifier is not
// allowed.
if (!globalScope.getProjectOptions().get(BooleanOption.USE_ANDROID_X)
        && globalScope.getProjectOptions().get(BooleanOption.ENABLE_JETIFIER)) {
    throw new IllegalStateException(
            "AndroidX must be enabled when Jetifier is enabled. To resolve, set "
                    + BooleanOption.USE_ANDROID_X.getPropertyName()
                    + "=true in your gradle.properties file.");
}

Currently as of 10/29/18, enabling useAndroidX seems to have 3 main usages. It seems like it won’t matter if you don’t use any of those 3 functionalities below.

But if the doc says, useAndroidX should be set to true if you use AndroidX and doesn’t give any other conditions, it sounds like it’s semantically good to leave it set to true.

Data binding
DataBindingExportBuildInfoTask.java

1
2
3
4
5
@TaskAction
public void run() {
    xmlProcessor.get().writeEmptyInfoClass(useAndroidX);
    Scope.assertNoError();
}

RenderScript
RenderScriptProcessor.java

1
2
3
4
5
6
7
8
9
10
11
12
13
if (mSupportMode) {
    if (mUseAndroidX) {
        builder.addArgs("-rs-package-name=" + FN_ANDROIDX_RENDERSCRIPT_PACKAGE);
    } else {
        builder.addArgs("-rs-package-name=" + FN_RENDERSCRIPT_V8_PACKAGE);
    }
}
...and...
public static File getSupportJar(String buildToolsFolder, boolean useAndroidX) {
    return new File(
        buildToolsFolder,
        "renderscript/lib/" + (useAndroidX ? FN_ANDROIDX_RS_JAR : FN_RENDERSCRIPT_V8_JAR));
}

Legacy dexing type
MergeManifests.java

1
2
3
4
5
6
7
8
9
10
if (variantScope.getVariantConfiguration().getDexingType() == DexingType.LEGACY_MULTIDEX) {
    if (variantScope
            .getGlobalScope()
            .getProjectOptions()
            .get(BooleanOption.USE_ANDROID_X)) {
        features.add(Feature.ADD_ANDROIDX_MULTIDEX_APPLICATION_IF_NO_NAME);
    } else {
        features.add(Feature.ADD_SUPPORT_MULTIDEX_APPLICATION_IF_NO_NAME);
    }
}

Comments are closed.

Categories