As we discover the rapidly growing world of React Native, we learn that it’s entirely possible to build an awesome application that leverages only the React Native code. While the Facebook team has done a fantastic job of implementing a lot of UIKit out of the gate, it’s conceivable that there will be times when you need to go beyond the boundaries of what React Native out of the box (and soon to be Android Java).
Perhaps you want access to the recently released Apple ResearchKit, or you want to be able to leverage custom networking utilities like AFNetworking. What we’ve learned from our time with React Native is that the possibilities are endless for the developers wanting to take advantage of this capability.
From what we’ve gathered in our research, there are two types of custom components that you can implement for React Native applications; user interface and utilities. For this article, we’re going to focus on the utility type, as it has less moving parts and is a great way to get your feet wet with building custom component code.
Developing a custom React Native component
The application we’ll develop is rather simple. It uses a custom React Native-enabled Objective-C class to write a random number to a file in your iOS application’s document directory and is a modified version of the custom PhoneGap plugin for iOS that I wrote in 2013. This class writes data in a non-encrypted format, so please don’t use it in production.
In a nutshell, this demo application will take a filename as input from a React Native TextInput component. The user will be able to load data from the Phone’s filesystem based the file name.
Upon pressing Save, a random number string will be generated via a simple Math.random().toString() method calls. The Load button performs the inverse, retrieving the contents of the file described in the TextInput and displaying it below. We do all of this as well as some basic exception handling as demonstrated in the animated gif below.
Instead of going through the rigmarole of the creating a React Native Project, we’ve decided to assemble an example and placed it in for you to easily checkout, execute and investigate for us to walk through together.
This github repo we created has two subdirectories, Phase1/ and Phase2/, both designed for you to review the implementation of each major phase of this article, as detailed above.
We’re going to kick this off with looking at the project structure itself.
A brief look at the project
Our example project is a generic React Native project with a small twist: instead of placing all of our React JS code at the root of the project, we place it inside of a folder known as jsx/.
The process for doing this is quite simple, as demonstrated below.
We perform this change for cleanliness of the project and suggest that anyone developing React Native applications consider something similar for it allows you to point your JSX editor to a directory that only contains the related JSX code, giving you the opportunity to visually locate files without having all of that XCode and Objective C mess cluttering your JSX editor’s UI. Proactive organization will only benefit our app development efforts.
Because we changed project structure slightly, we had to inform React Native. We do this by updating AppDelegate.m. The process for doing this can be observed below.
Before we can write any code, we’re going to need to inject our custom classes into the XCode project. There are three great reasons to do this via XCode and not via some external editor.
- When creating a Cocoa Touch class via this tool, the associated header file (.h), and program file (.m) are created with one process.
XCode will generate the class where we can define our class’s superclass, NSObject.
XCode will include our newly added class program to the list of files to be compiled (and linked).
We will perform this action using XCode’s “New File” menu system as illustrated below.
The Project is now structured as follows.
Now that we’ve got the basic scaffolding stuff out the way, we can actually start writing code. That’s why you’re here, right?
The first thing we must do is fill in the MCFileWriterUtil.h header file.
The header file consists of a very simple class definition, without the method signatures to do the work required. This is because we’re going to leverage special macros to define and expose our methods to the React Native bridge.
With the header written, we can go on to write the meat of the Objective C class scaffolding.
As you can see, the contents of the write and read methods are nearly identical at this stage. They are so because they are only setup for this learning phase.
There are three key takeaways from this phase of defining our custom Objective C class
From there, we can execute the method MCFileWriterUtil.writeFile(), where we pass in four arguments: file name, file contents, error and success handlers, both of which simply display a UIKit alert dialog with the string that is returned from the Objective C MCFileWriterUtil writeFile method.
If you train your eyes to the Objective C code we have our write method for the MCFileWriterUtil class, you can see that there exactly four arguments, two strings and two functions. When we execute a bridged method, we absolutely must call it using the defined arguments, or the bridge will throw an exception at you.
OK, cool. We got this bridge running. Our next job is to fill in the full contents of MCFileWriterUtil.m and write the code for the React JS implementation of our Objective C utility.
Phase two: Doing the real work
For Phase two, we are writing the actual Objective C code that does the actual work; writing and reading a file.
Here is the full implementation of MCFileWriterUtil.m. It’s heavily commented, so I will not dive into the details of how things are working.
Access this project in it’s entirety from our GitHub repo.
The future of developing plugins will change
It’s worth noting that one of the clear advantages of Facebook’s approach to releasing React Native is its Open Source licensing. This has allowed near-biblical flood of community discussions, and a quite a lot of pull requests from enthusiasts who are willing to contribute their time and energies to better the project.
One such project is aptly known as “Pull Request #405”, where Joe Stanton has contributed a scaffold generating utility for custom React Native iOS code. We’re hoping that this pull request is merged soon and once it is, we’ll update our example (and this blog post) accordingly.
Resources to learn more
The Facebook React Native team has done a fantastic job with documentation for the framework. We’re thankful that they’ve taken the time to document the patterns for developing custom React Native components, which can be found here. We highly suggest reading through it as it covers all of the patterns for developing custom React Native components for iOS.
In closing here’s a list of places people are discussing React Native: