The contents of this page describe what a Native Bridge is within React Native, and how to create one within a project.
Description
One of the many benefits of using the React Native framework is that it does not pigeonhole app development by limiting it to the current platform API or the many third-party libraries that are usually required to create and build a project. Sometimes development necessitates for the creation of a module that does not exist either within the platform API or where there is no comparable module found within the npm library at npmjs.org. React Native allows developers to create their own module(s) in Native Code (Objective-C & Java for MQ purposes). It allows developers to bridge these modules into the project so that the top-level JavaScript layer can interact with those modules and use them within that JS layer.
The contents of this page describe what a Native Bridge is within React Native, and how to create one within a project.
What is a Native Bridge?
When you hear the term 'Native Bridge', think of npm packages.
Many (but not all) React Native npm packages that are added/installed into a project are Native Bridges. If the package is a pure JS package, then that's just what it is - pure JavaScript. If a react-native package contains an `iOS` directory and an `android` directory, it is most likely a Native Bridge. Those two directories are typically where the Native code should live for each platform, which then connects to one or more JS files which should be included within the npm package. Once a package has been added or installed in the project, the developer normally imports the package via the earlier mentioned included JS files into a class within their project. Then, they are able to interact with the native code to perform some sort of functionality within that class. Some of the more common native elements that are often interacted with are the device camera, photo albums or adding events to calendars.
That whole ability to communicate from the Native module to the top JS layer within the app is what we refer to as a Native Bridge.
Creating a Native Bridge:
For this example we will create a very simply Flash module that checks a device for whether it has a flash or not:
Note: This is not a tutorial in Objective C or Java so I will not spend time explaining what the code does; Only why something is required for bridging purposes.
Step 1: Create the Native iOS code in Objective C
Open the React Native project in XCode as one should not create .h and .m files within PhpStorm of VisualStudio Code or whatever their preferred editor is. Creating these files should occur in XCode.
To create a file, choose the folder where you want the file to live within the project, (good place is where the main.m file resides) and right click, then select New File... and choose either the Header File or Objective-C-File and it will be added to the project. There will be some additional boiler plate options that you can choose, but starting with a blank class is always a good route to go.
Objective C generally requires a header (.h) file and a message (.m) file.
For the flash library we first create the '.h' file which looks like this:
Flash.h
|
The main take away here is that this header (.h) file implements the RCTBridgeModule protocol, which is required to bridge the native code to the JS code. For completion sake, it defines the Flash class that we are about to implement.
Next we have the message (.m) file and it looks like this:
Flash.m
|
React Native will not expose any methods of Flash module to the JS layer unless explicitly told to. This is done using the RCT_EXPORT_METHOD()
macro to wrap the hasFlash method of the Flash class.
The code above returns a Promise to the JS layer of either Success or Failure of the code run within the RCT_EXPORT_METHOD wrapper. That is it for the iOS Native code.
Step 2: Create the Native Android code in Java
Open the React Native project in Android Studio as one should not create .java files within PhpStorm of VisualStudio Code or whatever their preferred editor is. PhpStorm will not read the file type properly and you won't have access to proper intellisense.
We now need to drill down to the correct place to add our native Java Flash code. Within the top level android directory open the folders in this path `app → src → main → java → com.{project name} `
Within this directory, create a new directory and call it 'flash'. It is within this new directory that the flash module Java files will be created.
Right click the 'Flash' directory and select 'New → Java Class' and name it FlashPackage. Then we need to fill it with some code. When we are done it will look like this:
FlashPackage.java
|
This Java file implements the RCTBridgeModule protocol, which as we know from before, is required to bridge the native code to the JS code.
Next we have the flash module where the actual logic resides and and it looks like this:
FlashModule.java
|
Now that we have these 2 files created, we need to tell the MainApplication.java file to use this newly created Flash module. The MainApplication.java file is located in the parent directory to where we created the flash directory. It should be a sibling to the Flash directory. Open that file and within the import section we would add the following code:
Import
|
Next, we need to tell React Native about the package. Within the same MainApplication.java file look for a ReactNativeHost method and add your Flash package. The method should then look similar to this:
Add Flash Package
|
And with that we now need to move over to the JS layer and create our JavaScript file that will actually bridge the Native layer and the upper level JS layer.
Step 3: Create the TypeScript or JavaScript file for Native level interactions
We need to create a file that will talk to the RCT_EXPORT_MODULE() in the Native land and any methods to be used in JavaScript land. Now we can safely do this in PhpStorm or whatever code editor is your preference.
You can place this file anywhere you want that makes sense to you in your project. This example is done with TypeScript as that is the standard that we use in MQ projects. For Flash it looks like this:
Flash.ts
|
And with that, we can now import the Flash.ts file and it's method into other files within the project.
An example of what that looks like is this:
Example Usage
|
This implementation should return a Success or Failure and then console.log will display the correct response based on whether the returned promise was a value of success or failure.
And with that, this is what we would call a valid Native Bridge.
For further reading about Native Modules in React Native, see the official ios documentation here and the official android documentation here.