Skip to content

React Native Auto Linking on Android

You probably should if you are a mobile developer and haven’t tried React Native. React Native makes it easy to build simple, beautiful apps with almost just Javascript. It also allows developers to write native code for each platform (iOS, Android, Windows, and more) and use it via Javascript. These are called Native modules. There are plenty of libraries out there that helps you use some of the critical device features, such as Bluetooth, Wifi, and camera that uses native code and expose interfaces to Javascript via NativeModules fromReactNative module.

Here are some of the popular react-native libraries that also come with platform-specific native modules

Before RN 0.60, to use a library that is also a native module, we need to add the dependency and link it to our native projects so that it is included in our native builds. This can be done either using react-native link <dependency name> or manually if you have superpowers.

In the case of Android, the linking is as simple as adding the dependency project’s path to settings.gradle and adding an implementation <dependency package> in build.gradle and also include the package in your MainApplication.java file.

For example, if you were to add the library react-native-ble-manager For your project, you need to follow these steps:

Disclaimer: I stole these from their README

// file: android/app/build.gradle
...

dependencies {
    ...
    compile project(':react-native-ble-manager')
}
// file: android/settings.gradle
...

include ':react-native-ble-manager'
project(':react-native-ble-manager').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-ble-manager/android')

Add the lines to your MainApplication.java:

import it.innove.BleManagerPackage; // <--- import

public class MainApplication extends Application implements ReactApplication {

    ...

    @Override
    protected List getPackages() {
        return Arrays.asList(
            new MainReactPackage(),
            new BleManagerPackage() // <------ add the package
        );
    }

    ...
}

Note: This post concentrates on Autolinking on Android. Please take a look here at how it used to be for iOS: 👉 Linking iOS Libraries

For Android, two steps are involved in linking a native library to react-native projects. For each dependency,

  1. Include the dependency project in settings.gradle
  2. Include the implementation <dependency project> in our dependency {…} in build.gradle file.
  3. Include the package in our Application class.

As of React native 0.60+, the react-native cli was extracted out and maintained separately into the react-native-community/cli repo, which had a major version update. This update eliminates the need for us to manually link the native libraries after adding them to package.json.

Note: RN 0.60+ requires cocoapods for iOS and AndroidX for Android. I will write more about it in a separate post.

For example, if you were to add the same library react-native-ble-manager to your project with RN 0.60+, all you have to do is add react-native-ble-manager to your package.json. This makes it so much easy to maintain and easily update our dependencies.

How does this Auto-linking work for Android projects?

We discussed how to link native libraries manually before RN 0.60. Setting up Autolinking with RN 0.60+ is similar to the 3-step manual linking for each dependency. The below steps are just a one-time setup.

1. Including Project in settings.gradle

Instead of adding individual native libraries to our settings.gradle file, we include one script native_modules.gradle that comes with react-native-CLI 2.0+ and then invokes the function applyNativeModulesSettingsGradle(settings).

apply from: "../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"
applyNativeModulesSettingsGradle(settings)

2. Include the implementation for each dependency we added

This is similar to the previous step, and we include the gradle script native_modules.gradle again and invoke the function applyNativeModulesAppBuildGradle(project) which will take care of adding implementation <dependency project> automatically.

3. Include the package in our Application class.

The native_modules.gradle generates a class called PackageList which has all the dependencies’ packages included. We need to instantiate this class using the ApplicationContext and return it to the getPackages method of our Application class. If additional native modules need to be included, we can add them to this PackageList instance.

What is in the file native_modules.gradle that makes this process so simple?

We need to thank its Javascript counterpart for that. The react-native-cli has this pretty neat CLI tool config. This tool provides all the necessary information about the react native project, including the native dependencies that should be added to our native projects (iOS, Android, etc.). This is how it looks for a project that has a dependency. react-native-ble-manager :

$ npx react-native config
{
  "root": "/Users/bala/sample-app/Sample",
  "reactNativePath": "/Users/bala/sample-app/Sample/node_modules/react-native",
  "dependencies": {
    "react-native-ble-manager": {
      "root": "/Users/bala/sample-app/Sample/node_modules/react-native-ble-manager",
      "name": "react-native-ble-manager",
      "platforms": {
        "android": {
          "sourceDir": "/Users/bala/sample-app/Sample/node_modules/react-native-ble-manager/android",
          "folder": "/Users/bala/sample-app/Sample/node_modules/react-native-ble-manager",
          "packageImportPath": "import it.innove.BleManagerPackage;",
          "packageInstance": "new BleManagerPackage()"
        }
       "iOS":{…}
      },
      "assets": [],
      "hooks": {},
      "params": []
    }
  },
  "commands": [],
  "assets": [],
  "project": {
    "ios": {
      ...
    },
    "android": {
      "sourceDir": "/Users/bala/sample-app/Sample/android/app",
      "isFlat": false,
      "folder": "/Users/bala/sample-app/Sample",
      "stringsPath": "/Users/bala/sample-app/Sample/android/app/src/main/res/values/strings.xml",
      "manifestPath": "/Users/bala/sample-app/Sample/android/app/src/main/AndroidManifest.xml",
      "buildGradlePath": "/Users/bala/sample-app/Sample/android/app/build.gradle",
      "settingsGradlePath": "/Users/bala/sample-app/Sample/android/settings.gradle",
      "assetsPath": "/Users/bala/sample-app/Sample/android/app/src/main/assets",
      "mainFilePath": "/Users/bala/sample-app/Sample/android/app/src/main/java/com/sample/MainApplication.java",
      "packageName": "com.sample"
    }
  }
}

I removed most of the stuff in this output to keep it short. Take a closer look at the android property of dependencies.react-native-ble-manager.

"android": {
          "sourceDir": "/Users/bala/sample-app/Sample/node_modules/react-native-ble-manager/android",
          "folder": "/Users/bala/sample-app/Sample/node_modules/react-native-ble-manager",
          "packageImportPath": "import it.innove.BleManagerPackage;",
          "packageInstance": "new BleManagerPackage()"
        } 

The script uses this information to auto-link native libraries to our project automatically — for each dependency 🤯

Learn more about Auto-linking 👉 here

Pro Tip: When you migrate to RN 0.60+, you may need  unlink all your previously “linked” native libraries. You can do it by using npx react-native unlink <dependency name> . This removes the entry from your settings.gradle , build.gradle and MainApplication.java . If you have already moved your MainApplication class to Kotlin, this unlinking will not work. It would help if you unlinked manually, which is the reverse of manual linking.