Distributing React Native components with native code

Preben Aandahl
5 min readNov 14, 2016

--

Source: Remix of artwork from npmjs.com and the respective logos.

If you’ve ever tried to split out the native code of your React Native project into external packages, you might have encountered a severe lack of documentation. In this article, I will walk you trough a project layout for wrapping up your JS, Obj-C and Java code in a sweet little npm package that supports automatic linking when installed.

The 9 project layout

When working on my own react-native-filesystem, I couldn’t find any good guidelines for how to structure my native code, so I decided to create a boilerplate on Github with a HelloWorld component, hoping it could help someone else trying to accomplish the same.

The 9 project layout is not as retarded as it sounds: it’s three sets of projects with JavaScript, Objective-C and Java, for cross-platform iOS & Android code. I’ll walk you through them.

The root projects

The first set of projects is where your components (and modules) live. This is what will get published to npm, and nothing more. Technically, this is all you need. If you want to develop within the context of an existing application, you can link it directly with a relative path in your package.json and load changes with an npm install:

"dependencies": { 
"react-native-helloworld": "../path/to/code/"
}

However, you might want to enjoy the quick iteration of test-driven development, and make sure your code base stays stable as it evolves. That’s where the next three projects come in handy.

The test projects

The test projects contain unit-tests for your Obj-C code, unit-tests for your Java-code, and integration-tests written in Javascript.

If you open tests/ios/HelloWorldTets.xcodeproj in XCode, you'll find the root source code linked under Libraries/HelloWorld, and an example unit test under the HelloWorldUnitTests target. The HelloWorldIntegrationTests contains a test runner configuration that picks up integration tests from tests/integration-test. If you select a device to run on (f.ex. an iOS simulator) and hit ⌘+U, both of these test suites will run in the standard XCode test runner.

If you open tests/android in Android Studio, you can edit the native Java-code and unit tests side-by-side, and run your tests in the visual test runner by right-clicking on the test-package and selecting Run Tests in tests. As you can see, these are just standard JUnit-tests.

Finally, to run the integration tests on Android, run the tests app on a device or an emulator through Android Studio or react-native run-android.

You have to click on each test to run them for now, but I’m planning on adding an automated test runner also for Android in the future. The integration tests are written in JavaScript as React components, and if you open the tests/-folder in your JS-editor of choice, you can edit them in concert with the component code (which you'll find in the symlinks folder).

The test projects also provide a context for developing the component code with all dependencies (the root projects just link React/Native as peer dependencies).

A 6 project layout might be enough for some, but if you are making something more complex, you should consider including sample code.

The sample projects

The last three projects provide a full-fledged React Native application that demonstrates the practical use of your package. Again, this code is ignored when the npm package is bundled. Ideally, the XCode and Android-projects are nothing more than the boilerplate generated by react-native-cli.

As you can see, the main reason for having all these separate projects is to keep your distributable npm package lightweight. While developing, I work exclusively within the contexts of the three test-projects, and the JS-project of the sample.

The package.json of the root project includes the following configuration to let react-native-cli know where the Android code is located:

"rnpm": { 
"android": {
"sourceDir": "./android"
}
}

The XCode project with the iOS code is detected automatically. This means that once the package is published, it can be installed and linked like this:

npm install react-native-helloworld --save 
react-native link react-native-helloworld

Or, if you’re in a hurry, with a single command:

react-native install react-native-helloworld

If you have customised the boilerplate generated by React Native too much for the automatic linking to work, you can still link it manually. But what is it exactly that the automatic linker does?

Make sure the npm-package is installed:

npm install react-native-helloworld --save

iOS

Open your XCode project, right-click on the Libraries folder and select Add files to YourProjectName. Locate and select your-project/node_modules/react-native-helloworld/ios/HelloWorld.xcodeproj.

Go to your project settings, select your main target, make sure the General tab is selected, find the section Linked Frameworks and Libraries at the bottom, and add libHelloWorld.a.

Android

Add the two following lines to your-project/android/gradle.properties:

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

Then add the following line to the dependencies section of your-project/android/app/build.gradle:

compile project(':react-native-helloworld')

Finally, add the bold part to your-project/android/app/src/main/java/com/yourproject/MainApplication.java:

import com.benwixen.helloworld.HelloWorldPackage; 
...
public class MainApplication extends Application implements ReactApplication {
return Arrays.asList(
new MainReactPackage(),
new HelloWorldPackage()
);
...
}

Time to make components

That’s it for our layout. Now it’s time to go out and fill the many holes in the React Native ecosystem. Clone the boilerplate if you want a starting point.

With the right set of components, 80–100% shared code between platforms is within reach for most types of applications. Let’s make app development great again!

Via giphy.

Follow me on twitter: benwixen
Originally published at
www.benwixen.com on November 14, 2016.

--

--

Preben Aandahl

IT consultant working with frontend & backend on web & mobile.