How It Feels to Work with React Native If You're an Android Developer

React Native has become quite popular among mobile developers recently, so I just couldn’t resist the urge to get acquainted with this framework to keep pace with the newest trends in mobile app development.

Why React Native?

For those who are joining the party late, React Native is a JavaScript framework for writing “true” natively rendered applications for iOS and Android. React Native arose from Facebook’s JavaScript Library called React, which was designed to build interactive web user interfaces; but instead of targeting web browsers, React Native targets mobile platforms.

What this means for the web development community is that now web developers can build mobile applications that look and feel truly native, using their beloved JavaScript library. Moreover, because most of your code can be shared between platforms, it becomes possible to simultaneously build solutions for both iOS and Android. This is actually what intrigued me most, so I wanted to check if I could use React Native effectively in my future work.

Reviewing the project structure

Let’s get started! After everything is set up, you can create a project by entering a single command in the terminal:

react-native init TestProject

react native project view

[Project structure]

The structure of a newly generated project is pretty straightforward: it contains your Android and iOS projects, which can be opened via their usual IDEs – Android Studio and XCode – if needed. But while it’s possible to develop platform-specific parts of an application, the primary logic of the application will be located outside of the distinct Android and iOS projects.

The node_modules directory contains all of the included dependencies. index.android.js is the entry point for the Android app, while index.ios.js serves the same purpose for the iOS app.

Let’s choose an IDE

One of the trickiest things when you start with a new programming language is choosing the right editor for your project. Besides, in our case we have to find an editor suitable for cross-platform development, and I have a couple of insights on this matter...

I might go for Atom, a beautiful, lightweight, and easily customizable text editor with a nice autocomplete and convenient file system browsing. Of course, it hardly compares to Android Studio in a number of features, but it’s worth giving it a chance.

Also, you may find it useful to install the Deco IDE. It seems to be more functional than the previous editor and includes a graphical editor which could ease the building of your app’s UI. There are loads of options actually, but I personally made my choice in favor of Vim, a highly configurable, time-tested lightweight editor that supports hundreds of programming languages including JavaScript.

react native vim editor

[The Vim editor]

What about the UI?

Poor UI performance and the lack of native functionality support are common drawbacks of most apps written in JavaScript, HTML, and CSS. The reason why we might end up with poor UIs is probably the use of webviews for rendering in cross-platform development tools like Cordova, Ionic, and Titanium. React Native, however, takes quite a different approach.

Similar to their web-oriented fellows built with the help of React, React Native apps are written using a mix of JavaScript and XML-like markup known as JSX. Behind the scenes, React Native “invokes” its native rendering APIs in Objective-C (on iOS) or Java (on Android). What this means is that your application renders using native views (not webviews!), which makes the difference between an app written in Java or Kotlin (for Android) and an app written using React Native hardly visible (if not altogether invisible). Plus, React Native exposes JavaScript interfaces to the platform’s APIs, so an application written using the framework can access different built-in smartphone features such as GPS and cameras. We’ll get back to this a bit later. Now, let’s see what an app built with React Native might look like.

react native UI view

[Android and iOS UI views built using React Native]

In the example above, the code is the same for Android and iOS, but it’s a common case to have separate files for more difficult screens, which may be slightly different for each platform. My example proves that one development team can work with two different platforms using the same approach.

As you can see, the screen above looks native on both Android and iOS, and it actually is! I’ve used the nativebase.io library for this purpose, which makes creating the UI even easier.

The code above is written in JSX; its tags have tag names, attributes, and children just like the ones in XML.

export default class TestProject extends Component {
  render() {
    return (
      <Container>
        <Header
          style={{}}
          backgroundColor='#2c3e50'
          iosBarStyle='light-content'
          androidStatusBarColor='#1b2732'>
          <Left>
            <View style={{flexDirection:'row'}}>
              <Button transparent>
                <Icon name='arrow-back' style={{color:'white'}}/>
              </Button>
              <Title style={{color:'white', alignSelf:'center', marginLeft:26}}>TestProject</Title>
            </View>
          </Left>
        </Header>
        <Content>
          <Spinner color='#880E4F'/>
        </Content>
        <Footer>
          <FooterTab style={{backgroundColor:'#2c3e50'}}>
            <Button active style={{backgroundColor:'#1b2732'}}>
              <Icon name='share' style={{color:'white'}}/>
            </Button>
            <Button>
              <Icon name='alarm' style={{color:'white'}}/>
            </Button>
            <Button>
              <Icon name='build' style={{color:'white'}}/>
            </Button>
            <Button>
              <Icon name='globe' style={{color:'white'}}/>
            </Button>
          </FooterTab>
        </Footer>
      </Container>
    );
  }
}

That wasn’t so complicated, was it?

Java and Kotlin code interoperability

The most important thing for me was to find out if I could reuse libraries I’ve already written in Java or Kotlin. It would be a pity if they were useless for apps developed in React Native. Luckily for me (and for the whole community of mobile developers), it’s possible to use them as native modules. Java and Kotlin libraries can be used to implement any platform-specific functionality in a project.

Below, as promised, I’ll check if I can use the native features of the Android platform.

Let’s imagine that you need to open a camera preview, for example, without any existing solutions (for some reason) – and write this functionality in Kotlin.

The first step is to create a module to implement the required functionality – to open the camera in our case. Here, you can use Android Studio to edit the Android part of the project. I’ve created CameraModule, which extends ReactContextBaseJavaModuleclass in order to make it acceptable for our React Native project.

It’s necessary to implement the getName() function to be able to access this module later. And now it’s time to actually create a function to open the camera preview. The only requirement is to add an @ReactMethod annotation so that it can be visible to the JavaScript file.

After that, you need to create a descendant of the ReactPackage interface to add the CameraModule to. Now we’re only interested in the createNativeModules() function. Here, I return a list that contains the required module.

The only thing left is to add this package to the list of packages in the MainApplication class (no need to create it, it already exists in androidpackage).

After we’ve done the previous step, let’s import the created module to the index.android.js file and actually display the camera.

​import { NativeModules } from 'react-native';

const camera = NativeModules.CameraModule;

To add a listener for a button, I used the onPress attribute:

​<Button onPress={()=>camera.openCamera}/>

How do we get the photo uri back into the js file? First, it’s necessary to implement an ActivityEventListener and pass its descendant to the reactApplicationContext.addActivityEventListener() function in the constructor of the module. Let’s review the updated CameraModule:

class CameraModule(context: ReactApplicationContext?) : ReactContextBaseJavaModule(context),
        ActivityEventListener {

    companion object {
        private const val CAMERA_REQUEST_CODE = 1
    }

    init {
        reactApplicationContext.addActivityEventListener(this)
    }

    private var callback: Callback? = null
    private var errorCallback: Callback? = null

    override fun getName() = "CameraModule"

    @ReactMethod
    fun openCamera(callback: Callback, errorCallback: Callback) {
        this.callback = callback
        this.errorCallback = errorCallback
        reactApplicationContext.startActivityForResult(
                Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE),
                CAMERA_REQUEST_CODE, null)
    }

    override fun onActivityResult(activity: Activity?, requestCode: Int,
                                  resultCode: Int, data: Intent?) {
        if (requestCode == CAMERA_REQUEST_CODE) {
            if (resultCode == Activity.RESULT_OK) {
                callback?.invoke(data?.data?.toString() ?: "")
            } else {
                errorCallback?.invoke("No image")
            }
            callback = null
            errorCallback = null
        }
    }

    override fun onNewIntent(intent: Intent?) = Unit

}

onActivityResult() and onNewIntent() are the only functions of the interface.

Let’s update the openCamera()function call:

function openCamera() {
  camera.openCamera((uri) => {
      console.log(uri);
    },
    (error) => {
      console.log(error);
    }
  );
}

To review logs from the device, use these commands:

react-native log-android
react-native log-ios

Last but not least – existing solutions

Sometimes you face a challenge that you can’t resolve quickly and easily, and if you develop applications using React Native you’ll certainly encounter a difficult situation sooner or later. Fortunately, there are plenty of small and large JavaScript libraries that may help you out of any fix – when you don’t know how to provide strings localization or integrate your project with Firebase cloud messaging, for instance. Most of these libraries can be easily installed into your project using the npm package manager. Just use the command below and start using a new functionality:

npm install <library_name>

You can find all available libraries here.

Well, that’s it for today, but it’s definitely not the end. I’ll continue experimenting with React Native and, of course, I’ll try to keep you updated on my findings.

3.8/ 5.0
Article rating
6
Reviews
Remember those Facebook reactions? Well, we aren't Facebook but we love reactions too. They can give us valuable insights on how to improve what we're doing. Whould you tell us how you feel about this article?