Migrate a current project to AndroidX  – A not so love story

Last week, I started migrating a current project to AndroidX libraries. The app was originally built in 2015 so it contains some older code. I followed the android documentation how to migrate an existing project to AndroidX. According to the documentation, the migration is quite simple… Well it’s not.

AndroidX

In september 2018, Google released their 1.0 stable version of AndroidX. AndroidX is a major improvement to the original Android Support Libraries. Unlike the Support Library, AndroidX ships separately from the Android OS and provides backwards-compatibility across Android releases. AndroidX fully replaces the Support Library by providing feature parity and new libraries.

Let’s start with the migration

First I updated my Android Studio to 3.2. Then I updated the gradle plugin version of the project. From then I was able to migrate to AndroidX using Android Studio. In Android Studio go to Refactor > Migrate to AndroidX. At that moment a lot of files are being changed. Most of the changes looked like this. 

The application uses some third party libraries. Because of that we needed to do some extra setup for our migration. In the gradle.properties file we needed to add these properties.

Jetifier

The standalone Jetifier tool migrates support-library-dependent libraries to rely on the equivalent AndroidX packages instead. The tool lets you migrate an individual library directly, instead of using the Android gradle plugin bundled with Android Studio.

Let’s Build

After some cleaning and minor fixes I was able to build the project. I started the application and at first sight everything looked ok!. Nice, isn’t it?! So I made a build for our client. At this moment I was satisfied, the migration wasn’t too hard and the application worked fine at first sight on my emulator and physical device. 

The app crashed at startup…

My satisfaction didn’t took long. Our client reported that the app crashed at startup. As usual with crashes I went to our crash reporting tool to see the issue. After some debugging I found the issue. In the project we used this library. We updated the version of this plugin to the latest version. This was a fix for the startup crash. But wait, … I enabled Jetifier right? Why didn’t the app crashed on my device? This tool should help me to avoid that I use a version of a third party library that is not compatible with AndroidX. I really recommend you to check all your third libraries and it’s AndroidX compatibility.

Hi client, new build on its way…

It works on my machine…

Above fixes didn’t prevent the crash on my clients devices. At that moment I started searching for what could be the difference between the build on my machine and the build that was distributed by Beta. The reason was quite straightforward. In our project we’ve had 2 buildtypes, Debug and Release.

Here I saw the difference between the builds. You can see in our release build that we minified our application by using custom ProguardFiles. After some searching I found this quote on the internet.

“Using default Proguard rules can save you time and pain, especially (but not limited to) when migrating to AndroidX.”

Oh yeah, this is gonna be nice a one, we use custom Proguard files 🎉 ….

Apparently, the AndroidX migration tool didn’t update the Proguard rules… First I started searching through the project for android.support.(widget) Every line of code I changed to androidx.(widget).

And then I needed to change these lines of code.

R8

At that moment I realised the migration was not as simple according to the Android documentation. There were a lot more things I needed to change than just migrate to AndroidX libraries. The above fixes prevented the release build to crash at startup but the application was not working as before… Some resources not found, classes not found, …At that moment there was a 3 letter word in my mind.

By rebuilding the project, the logs got my attention…

According to Android documentation, when you use Android Studio 3.4 or Android Gradle plugin 3.4.0 and higher, R8 is the default compiler that converts your project’s Java bytecode into the DEX format that runs on the Android platform. We took that shot by disabling R8. Maybe this would be the reason that our app was not working like before.

android.enableR8=false

For more information about R8 I really recommend you to take a look at this blog post.

By setting this property everything looked fine and wasworking like before. Complete-program optimization is hard! ProGuard has 15 years of development and testing. Millions of developers have applied it to millions of apps, which has yielded a wealth of feedback on common code and unusual code. The Android R8 is much younger, with a team actively improving its stability and extending its functionality.

Conclusion

We wanted a stable product using AndroidX libraries and a release build that was shrinked and obfuscated. The goal was to migrate our current project to AndroidX. This goal was reached. The extra tooling for shrinking and obfuscation was an addition to this goal. It seemed that we needed to do a lot of extra configuration to work with R8 and Proguard while our custom Proguard was steady and proven.

So keep in mind, AndroidX migration is more than change the Android Support Libraries to AndroidX libraries and can be hard in existing big projects.

Have any questions about this blog? Contact me via jordan.de.vogelaere@jidoka.be

Interesting links 

https://proandroiddev.com/what-are-you-keeping-from-me-44ece21f4631

https://www.guardsquare.com/en/blog/proguard-and-r8

https://developer.android.com/jetpack/androidx/migrate