Debugging common React Native issues on Android

debugging-react-native-android-header.png

This article examines common issues encountered when building apps for Android using React Native. It shows errors you're likely to see, and how to resolve them. It also offers tips on troubleshooting.

Introduction

In this tutorial, we’ll take a look at how to debug some of the most common issues you will encounter while developing Android apps with React Native. Specifically, we’ll be looking at the following issues:

  • Software dependency problems
  • Third-party package issues

Prerequisites

This article assumes you know how to develop apps with React Native. It also assumes that you have set up your computer for React Native development.

This article assumes you know your way around the operating system you’re using, especially when executing commands in the terminal or installing software.

Debugging checklist

In this section, we’ll take a look at a general debugging checklist that can help you identify the actual issue that you’re having.

  • Did you find out everything you can about the issue you encountered? I know it seems obvious, but the first step for debugging is to find out everything you can about the error or issue at hand. Search for the issue on Google, then tweak your query to something simpler or more general. The results might not be the same issue you’re having, or the solutions might not help. But each one should give you a better idea of what the real problem is.
  • Did you read and double-read the docs? Again, this seems obvious, but a lot of times the issue is just a typo (For example, incorrect prop names, invalid prop values). Be sure that you’re actually using the correct names for the props that you’re using. If it’s a method, double-check if the arguments you’re passing have the expected data type and structure.
  • Are you sure your code does what you think it does? If there’s a bug in your code, the first step is for you to describe what each line of code does. Comments are great for this. Walk yourself through your own code so you can verify if it indeed does what you think it does.
  • Did you check for the issue on Github or Stack Overflow? Oftentimes, someone has already encountered the issue that you’re having. It might not be the exact same issue but going through their debugging process will help you get an idea of what else you’ve missed. Additionally, once you’ve debugged the issue, feel free to leave a comment on how you’ve solved it to help others that will encounter the problem in the future.
  • Did you properly install all the dependencies that your project requires? If there’s a problem with a package you installed, and you’re sure it’s working before you installed that package, the first thing you can do is to remove the package and re-install it again.
    If it still doesn’t work after that, create a new React Native project and copy your existing code to that new project. After that, go through the installation process again and take note of any issues that you encounter.
  • Did you uninstall the app before building it? Sometimes the problem is that some of the components from the previous app builds still lingers within the device or emulator. Doing a clean uninstall makes sure that no previous code is still on the device.
  • Did you re-install all the dependencies and made sure the project is using correct native packages? If you’re trying to get a native module to work, and you’ve followed the install instructions to the letter. But still it wouldn’t work, the solution may be to clear out your node_modules and re-install all the packages:
1rm -r node_modules
2    npm install

After that, execute the following:

1cd android
2    ./gradlew clean

This will delete the build directory and make sure that no previous code or resources are still being cached.

You may even go one step further by clearing out the Gradle’s dependency cache:

1./gradlew build --refresh-dependencies

Once that’s done, go back to your project’s root directory and execute react-native run-android like usual.

Software dependency problems

In this section, we’ll be looking at problems you might encounter if you haven’t installed all the software dependencies for React Native for your operating system. Or if there are problems with the tools used for building the app.

Android path not added to the environment

The first time you build your Android app after setting up your computer for React Native development, you might encounter an issue similar to the following:

Error Android path not configured

The terminal says the problem is:

1FAILURE: Build failed with an exception.
2
3    * What went wrong:
4    A problem occurred configuring project ':app'.
5    > SDK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID_HOME environment variable.

This happens when you haven’t properly configured your environment variables to use the path where Android is installed. React Native requires this if you’re running the app on Android.

To solve the issue, you need to add the Android path to your environment variables.

In Ubuntu, this can be done by editing the .bash_profile file located in your home directory:

1nano ~/.bash_profile

Add the following to the file then save it:

1export ANDROID_HOME=$HOME/Android/Sdk
2    export PATH=$PATH:$ANDROID_HOME/tools
3    export PATH=$PATH:$ANDROID_HOME/tools/bin
4    export PATH=$PATH:$ANDROID_HOME/platform-tools

Then you can execute the following command to propagate the change to your system:

1source ~/.bash_profile

For Mac OS, you can also make use of the ~/.bash_profile file. Here’s the equivalent:

1export ANDROID_HOME=/Users/$USER/Library/Android/sdk
2    export PATH=${PATH}:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools

Required Android packages not installed

Another issue which you might encounter when first starting out is that the Android packages required by React Native are not installed.

You can solve this by opening Android studio, then click on the configure button and select SDK Manager. That should open the following window:

SDK Manager

Check the same packages I’ve checked above. Here’s the text version:

  • Android 6.0 (Marshmallow)
    • Google APIs
    • Android SDK Platform 23
    • Intel x86 Atom_64 System Image
    • Google APIs Intel x86 Atom_64 System Image

Next, under the SDK Tools tab, the requirement is Android SDK Build-Tools version 23.0.1.

SDK Tools tab

Go through the installation process and that should solve the issue. Note that the items I’ve checked are the ones that are required by React Native.

If you’re using Google Play services in your project, you should install the following packages from the SDK Tools as well:

  • Google Play services
  • Support Repository
    • Android Support Repository
    • Google Repository

Emulator problems

Emulators are an indispensable part of the app development process. They allow us to test the app on different devices from our development machines. But along with the convenience they afford, are problems which only occur when using them.

For Android, the most common problem is the lack of the Google Play service within the emulator. If you’re using a native module which uses the service or if you’re using it directly from your app, then you may get the following error when using emulators. This is especially true if you’re using Genymotion or the Android emulator in Android Studio:

Google Play Services missing

In the screenshot above, the app is complaining that it won’t run without the Google Play services.

If you’re using Genymotion, you’re in luck because they’ve added a really easy way to install Google Play services. Simply click on the Open GAPPS button located at the upper right side of the window and just go through the installation wizard.

Open GAPPS in Genymotion

Once it’s installed, restart the virtual device and you should be good to go.

Build tool problems

Sometimes, you’ll also encounter problems with the build tools that React Native uses for building the app or running the development server.

Watchman

React Native uses Watchman to watch the project files for changes. This allows you to automatically rebuild the app so the changes will be reflected on the emulator or device as you’re developing.

Here’s the error that you’ll usually get if there is a problem with Watchman. This problem usually occurs in Ubuntu, but it can occur in other operating systems as well:

Error with Watchmen

The build log says the error is:

1Could not run adb reverse: Command failed: /home/wern/Android/Sdk/platform-tools/adb -s 192.168.56.101:5555 reverse tcp:8081 tcp:8081

Unfortunately, Googling the error “could not run adb reverse react native” doesn’t really return results which point out to the actual cause of the problem. It only gives us the idea that something is wrong with the development server.

To solve this issue, you need to run the development server separately. You can do that by executing react-native start.

This returns the actual error which prevents the development server from running automatically:

Watchmen error details

If you are to take anything out of the screenshot above, it’s this:

1inotify-add-watch(/home/wern/dev/mobile/TestProject/android/app/build/intermediates/incremental/mergeDebugResources/merged.dir) -> The user limit on the total number of inotify watches was reached; increase the fs.inotify.max_user_watches sysctl
2
3    All requests will continue to fail with this message until you resolve 
4    the underlying problem.  You will find more information on fixing this at
5    https://facebook.github.io/watchman/docs/troubleshooting.html#poison-inotify-add-watch

Unfortunately, the solution presented isn’t really very helpful. Especially if you don’t have much experience with Linux commands.

Here’s are the commands which you need to execute:

1sudo sysctl fs.inotify.max_user_instances=99999
2    sudo sysctl fs.inotify.max_user_watches=99999
3    sudo sysctl fs.inotify.max_queued_events=9999

This raises the limits of the inotify-watches to a really high value. Setting it to a value of 99999 is like saying to Watchman to use however much resource it needs to watch the directories. Because the underlying issue here is that Watchman wasn’t able to allocate the resources it needs because the default values were too low.

After that, shut down the Watchman server so the changes will be reflected in the system:

1watchman shutdown-server

Once that’s done, executing react-native start should work smoothly. You can even skip it and just run react-native run-android because that will also run the development server in the background. Be sure to terminate the currently running process before you proceed (press Ctrl + C or Cmd + C on your keyboard).

Gradle

Gradle is the build tool used for Android app development. React Native also taps into it in order to build and compile the app to an executable .apk file.

The most common problem that you might encounter, especially when your project is using a lot of third-party native modules, is the collision of Gradle dependencies. Collisions occur when two or more native modules are using different versions of native dependencies.

The most common among the native dependencies which cause a collision is the Google Play service. Any native module which uses Google’s services (for example, Firebase, Google Maps, AdMob) imports Google Play services as one of its native dependency.

The good news is someone has already written about this subject in really nice detail, so I’ll just point you out to the article: How to solve Google Play Services version collision in Gradle dependencies.

In the future, it’s always a good idea to check whether you’ll have a potential collision before installing a specific module. You can do that by opening the android/app/build.gradle file on the modules Github repo.

For example, here’s the build.gradle file of the React Native AdMob module. Check the packages under the dependencies to find out whether you will have a collision. And then use the article I’ve pointed out above as a guide for dealing with the collision:

1dependencies {
2      compile 'com.facebook.react:react-native:+'
3      compile 'com.google.android.gms:play-services-ads:+'
4    }

Third-party package issues

In this section, we’ll be looking at issues commonly encountered when using third-party packages (For example, the ones you install via npm or Yarn).

As a case study, we’ll be looking at React Native Maps. In my opinion, it’s the most notorious React Native package for breaking builds. Especially if you’re using it with other packages that depend on different versions of libraries that React Native Maps relies on.

I’ll walk you through an empty project which will use React Native Maps. At the time of writing this article, you’ll most likely have problems with getting React Native Maps to work. So we’ll try to install the package and solve any issue that we encounter.

Installing React Native Maps

If you haven’t generated a new React Native project yet, go ahead and create one:

1react-native init TestProject
2    cd TestProject

Once that’s done, install React Native Maps:

1npm install --save react-native-maps

If you read the installation instructions for Android, it says that you should add the following to the android/app/build.gradle file:

1...
2    dependencies {
3      ...
4      implementation project(':react-native-maps')
5    }

But checking the current contents of the dependencies, you’ll see the following:

1dependencies {
2        compile fileTree(dir: "libs", include: ["*.jar"])
3        compile "com.android.support:appcompat-v7:23.0.1"
4        compile "com.facebook.react:react-native:+"  // From node_modules
5    }

Right off the bat, you’ll notice that implementation project(':react-native-maps') doesn’t seem to fit in. And fair enough, you’ll see someone having an issue with this bit of code.

Someone replied to that thread and they said that the project should use Gradle 3 in order for the code to work.

But if you’re like me and you’re using a bunch of other native modules on your project, then this advice isn’t really going to work. Gradle is the build tool which compiles the project into an app. So using a different version for different packages isn’t going to work. All the native modules that you’re using for your project should use Gradle 3.

If you check the projects with the most number of stars on Awesome React Native and go to their android/build.gradle file. You’ll notice that most (if not all) of them are still using a lower version of Gradle (ranging from Gradle version 1 to 2):

Gradle version in 3rd part dependency

As a web developer with limited knowledge on native Android app development, converting the existing code of each of the modules that I’m using to Gradle 3 syntax isn’t really the best use of my time. Especially if there is a deadline to meet.

So what’s the solution?

Unfortunately, the only solution is to downgrade to a lower React Native Maps version. One that still uses the same Gradle version as most of your native modules. Note that downgrading to a lower version means you won’t get the latest improvements for the library.

Start by uninstalling React Native Maps:

1npm uninstall --save react-native-maps

If you have already gone through the installation steps, undo them by undoing the installation instructions.

Next, go to React Native Maps’ releases page and install the latest version which doesn’t use Gradle 3. In this case, it’s version 0.20.1. Because if you check the release notes of the version that came after it, it said “Updated gradle configuration for gradle 3.0.0+”.

Go ahead and install it:

1npm install --save react-native-maps@0.20.1

After that, follow the installation instructions for that version.

After making all the changes, try running react-native run-android again.

If you’re like me and you haven’t installed the Android packages required by React Native Maps, you should get an error similar to the following:

Third part package dependency error

The error is:

1[Android SDK Build-Tools 25.0.3, Android SDK Platform 25].
2               Before building your project, you need to accept the license agreements and complete the installation of the missing components using the Android Studio SDK Manager.

You can solve the issue by opening the SDK Manager from Android Studio. And under the SDK Tools, check version 25.0.3 under Android SDK Build-Tools:

SDK Tools to get dependency

After that, and it still doesn’t work, be sure to check out the Troubleshooting section on the React Native Maps’ repo for the specific version that you’re using.

Conclusion

That’s it! In this tutorial, we’ve taken a look at some of the techniques you can use to debug issues you’ll commonly encounter when developing apps with React Native. Hopefully, this article has given you a better idea of how to go about debugging these kinds of issues in the future.