I recently worked on a legacy React Native app that had issues running on Android. Like many software projects there is never enough time nor enough engineers so the project was not tested for Android. When they finally got around to running the app on Android it was too painful. I was asked to fix it.
Before going over the lessons learned lets explain what AndroidX is and why it has caused the react native community so much pain? Google essentially fixed the naming conventions of many of its core libraries. That’s all AndroidX is. Within normal Android projects developed in Android Studio the upgrade path was easy. But not for RN.
In RN we do not typically compile the native dependencies. We instead rely on the dependencies to deliver a compiled file that can be linked by RN. So we have a hard division, RN apps 0.59 and below or RN apps 0.60 and above.
Do you have a situation where you are on RN 0.60 or above, but one of your dependencies has not upgraded to AndroidX yet? Jetifier will search through your npm dependencies, detect old android imports and modernize them. If you are on RN 0.59 or below you do not need to run jetifier. If you are on RN 0.60 and above jetifier is run for you automatically.
One of the first things I addressed was getting the project to build properly
on the javascript side. For serious projects you should specify the nodejs
version that is known to work. In package.json
there is an engines
field. You should review and pick an LTS version of nodejs
you are committed to making the project run on. You may end up with something
like
While you are at it you can use asdf and specify the
language runtimes required for your project. You can add a .tool-versions
file
that reads like
Note: some javascript libraries depend on python2 being available to build correctly.
Once you have npm install
running correctly be sure to add package-lock.json
in version control. Yes it should be tracked as that is a set of dependencies
that is known to work for the project.
Now you try to build your app $ react-native run-android
but you see errors
like
These types of errors seem to map one to one to entries in
android/app/build.gradle
in the dependencies
group. You should specify the
exact version of the dependency to make the build complete.
If your project is heavily customized it may be hard to even know what a correct
RN app looks like. For extreme cases you can compute a diff on the config files
against the example app for your RN version.
Luckily the RN team has provided example builds for every
version of RN. E.g. RN 0.57 build.gradle file.
These examples are accessible by picking the correct branch and opening
the local-cli/templates
folder. Note, these are the example apps that are
generated by the cli when you initialize a new project.
To get the app building I specified the android sdk version. This in turn required using a version of gradle around 5.x (5.6.2 for us). Something that confused me a lot was the mismatching numbers between the gradle version and the android plugin for the very same gradle version. You want to set the plugin to version 3.5.0. The gradle syntax for the wrapper task also changed between these gradle versions. You end up with
You also need to upgrade the gradle version in android/gradle/wrapper/gradle-wrapper.properties
If your app is RN 0.59 and below be sure to use dependencies that do not use
AndroidX. This means reading through the dependencies releases on github, e.g.
https://github.com/react-native-community/async-storage/releases and looking
for the last release that was published before June 2019 (or thereabouts,
read the release notes for the first mention of AndroidX). You can quickly list
the possible versions by running $ npm view <package name> versions
.
You can also review dependencies generated by gradle. You will be shown output like
This region of gradle output lists some AndroidX dependencies being brought into
the project. Following Top-Master’s stackoverflow answer, we see that firebase-core
is pulling in some AndroidX dependencies. In this particular case we can search the
firebase release notes for the string androidx
and see an annoucement on June 17th that the library was migrated over to AndroidX.
Our android/app/build.gradle
file listed
which we can see from the notes was released after June 17th. The fix was to downgrade this to 16.0.8.
You will have to repeat a similar process for every dependency that is not building correctly for you.
This project was using react-native-firebase. For these projects be sure to consult the compatibility table. Mainly you’ll want the correct version of play services listed in your build.gradle file
This project was complaining about realm building. For this I ended up upgrading the dependency so it could build correctly with gradle 5.x. Similar process, I read through the releases and found the smallest version that would work with a modern gradle version.
If you have any tips I missed please share them. You can use the upgrade helper to know what to change. One final gist that helped on this project.
If you need help solving your business problems with software read how to hire me.