How to create an unstoppable service in React Native using Headless JS (Android) 
Tags: headlessjs, service, android, reactnative
Published: 2019-05-18 18:32:42

---
title: How to create an unstoppable service in React Native using Headless JS (Android) 
published: true
description: 
tags: HeadlessJS, Service, Android, React Native
conver_image:
---

![Alt text of image](https://thepracticaldev.s3.amazonaws.com/i/9a2xhsasrqrt29x3s5wz.gif)
<figcaption>Unstoppable</figcaption>

If you have already developed a mobile application with a relative complexity, probably you found yourself breaking your head out with some tasks that are not so common. This already happened to me in the development of our app at [Segware](https://www.segware.com.br/) integrating events of a specific hardware. The challenge was that every event should be processed by the app regardless the state of it, i.e, with the app in foreground, background, closed or even when it was not started (device reboots).

In this case, it's necessary to have something not attached to the application but in the same time it must be **unstoppable**, alive almost one hundred percent of the time to execute the tasks. In a native android application, it's could be done with the use of a component called [Service](https://developer.android.com/guide/components/services?hl=pt-br) that is able to execute tasks without an UI thread or a user action. 

The main goal of this article is to explain how to implement a native android module to execute this kind of task in a React Native (RN) application, with the use of services, broadcast receivers and [headless JS](https://facebook.github.io/react-native/docs/headless-js-android). In this article I used as example a simple **heartbeat** application and I will show how I created it step by step.

##Step 1 - Creating the Bridge

![bridge](https://thepracticaldev.s3.amazonaws.com/i/behlwr5w32atbrjqxcx7.gif)
<figcaption>Bridging</figcaption>

For a full understanding, I will present a tiny brief of how to implement a bridge to a [native module](https://facebook.github.io/react-native/docs/native-modules-android) in RN. If you like automatic process or want an easier way to do that I recommend using [react-native-create-bridge](https://github.com/peggyrayzis/react-native-create-bridge#react-native-create-bridge) or if you very familiar with this step, you can skip right to step 2.

In the actual context, a bridge is a *means of communication* between the RN layer and the native layer. Just as the documentation says, to create a bridge, firstly you must provide a **Package** responsible to register your module or UI module (not used here) in the RN layer. As shown in the class below, it's instantiated the module passing the react context as a parameter.

```java
// HeartbeatPackage.java

public class HeartbeatPackage implements ReactPackage {

    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        return Arrays.<NativeModule>asList(
                new HeartbeatModule(reactContext)
        );
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}
```

The **Module** itself is responsible for defining the methods and props that will be available to the RN layer in the native layer. To expose a Java method, it must be annotated using *@ReactMethod* and the return will be always *void*. The bridge is asynchronous, so the only way to pass a result to RN layer is by using callbacks or emitting events.

```java
// HeartbeatModule.java

public class HeartbeatModule extends ReactContextBaseJavaModule {

    public static final String REACT_CLASS = "Heartbeat";
    private static ReactApplicationContext reactContext;

    public HeartbeatModule(@Nonnull ReactApplicationContext reactContext) {
        super(reactContext);
        this.reactContext = reactContext;
    }

    @Nonnull
    @Override
    public String getName() {
        return REACT_CLASS;
    }

    @ReactMethod
    public void startService() {
        // Starting the heartbeat service
        this.reactContext.startService(new Intent(this.reactContext, HeartbeatService.class));
    }
}
```

To finish the bridge, it's just needed to connect it to the two sides. In the *MainApplicaiton.java*, automatically created with the RN project in the android folder, you must instantiate the new module in the *getPackages* method. Once you have done so, the methods and props of the module will be available and you can import and use then like below.

```javascript
// Heartbeat.js

import { NativeModules } from 'react-native';

const { Heartbeat } = NativeModules;

export default Heartbeat;
```

**Important**: The module's name must be the same defined by the REACT_CLASS variable in module class.

##Step 2 - Creating the Service

As commented before, a service is used to execute tasks detached from the main thread of the application. In this example, the created service is responsible, when it's started, to send heartbeats events in a specific interval of time. There are some ways to implement an interval in android, but here I used a [Handler](https://developer.android.com/reference/android/os/Handler) to process a runnable object and send the event every 2 seconds.  The *RCTDeviceEventEmitter* can signal events to RN layer and it can be obtained directly from the react context, like below. 

```java
public class HeartbeatService extends Service {
    ...
    private Handler handler = new Handler();
    private Runnable runnableCode = new Runnable() {
        @Override
        public void run() {
            context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("Heartbeat",null);
            handler.postDelayed(this, 2000);
        }
    };
    ...
}
```

The documentation of [Android Services](https://developer.android.com/guide/components/services#Basics) is very clear about how would be the impact of the android's system manager on your service. If it finds out that your device is in critical operation like low memory or low battery, it will kill some services to free these resources. To prevent this from happening, you have to turn your service to a [Foreground](https://developer.android.com/guide/components/services#Foreground) kind and to do so a notification must be fixed on the status bar of the device. With this, the notification were included in the *onStartMethod* of the service class, like below.

```java
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        this.handler.post(this.runnableCode); // Starting the interval
        // Turning into a foreground service
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("Heartbeat service")
                .setContentText("Running...")
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentIntent(contentIntent)
                .setOngoing(true)
                .build();
        startForeground(SERVICE_NOTIFICATION_ID, notification);
        return START_STICKY;
    }
```

**Important**: For the service to work, it's also necessary to declare it in the **AndrodManifest.xml**. [See this](https://developer.android.com/guide/components/services#Declaring).

##Step 3 - Creating the BroadcastReceiver

A [BroadcastReceiver](https://developer.android.com/guide/components/broadcasts), as the name itself says, it's a responsive component to broadcast messages from the android system or from another apps, similar to the publish-subscribe design pattern. There are many broadcast messages available in an android system, but in our case the most important one is the **BOOT_COMPLETED**. It tells us that that the device suffered a reboot operation and this process is finished.

Listening to this specific message, our broadcast receiver will be able to restart the service created before some seconds after the device reboot process finishes, which will keep sending the heartbeat events. The implemented code is shown below. 

```java
// BootUpReceiver.java

public class BootUpReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        context.startService(new Intent(context, HeartbeatService.class));
    }
}
```

In the **AndrodManifest.xml**, it's also needed to declare the broadcast receiver and define the message that it will be listening. The corresponding permissions to read this kind of message must be provided as well.

```xml
<manifest...>
    ...
    android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    ...
    <application...>
        ...
        <receiver
            android:name="com.rnheartbeat.BootUpReceiver"
            android:enabled="true"
            android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>
     </application>
</manifest>
```

##Step 4 - Creating the Application

Certainly, this is the simplest step of this tutorial but in the same time it's the most exciting one. It shows the result of everything done so far. In the RN layer, we need implement a component to interact and shows to the user the heartbeats events and I thought that the most suitable example to this event will be a heart pulse action, so let's do it. 

![Heartbeat](https://thepracticaldev.s3.amazonaws.com/i/gicupktjk7q983quqa20.gif)
<figcaption>Heartbeat</figcaption>

In the *App.js* of the RN project I created a simple component as you can see below. With the benefits provided by the *useState* and *useEffect* of [React Hooks](https://reactjs.org/docs/hooks-intro.html), a listener is registered and every heartbeat event will change the width and height of a heart image. Simple enough, right? Moreover, the press of a button component calls the *startService* method from the native layer.

```javascript
const App = () => {
  const [heartBeat, setHeartBeat] = useState(false);

  useEffect(() => {
    DeviceEventEmitter.addListener('HeartBeat', () => {
      console.log('Receiving heartbeat event');
      setHeartBeat(true);
      setTimeout(() => {
        setHeartBeat(false);
      }, 1000);
    });
  });

  const imageSize = heartBeat ? 150 : 100;
  return (
    <View style={styles.container}>
      <View style={styles.view}>
        <Image source={heart} style={{ width: imageSize, height: imageSize }} resizeMode="contain" />
      </View>
      <View style={styles.view}>
        <TouchableOpacity style={styles.button} onPress={() => Heartbeat.startService()}>
          <Text style={styles.instructions}>Start</Text>
        </TouchableOpacity>
      </View>
    </View>
  );
};
```

Finally, this is the time to test our application. As commented in the beginning of this article, the app to be approved in our test, it must to process the events in its 4 states (foreground, background, closed or not started). In the first state, when the app is shown to the user, it performs like the gif below. When the service is started a notification is pop up in the status bar of the device. 

![Running](https://thepracticaldev.s3.amazonaws.com/i/0r1v46zoup34d4lla0d4.gif) 

Probably, you are wondering about how we could see the processing of the event in the other states of the app. That's when we run the command **react-native log-android** in the root folder of the project. Running this in a command line we can se the *console.log* executed by the service when the app is in background or closed, like below.

![Console.log](https://thepracticaldev.s3.amazonaws.com/i/rraevjlq2jpyhbvvom2e.png)

Ok, now we see that the application in doing well, but the test when the app is not started is missing. We expect that the broadcast receiver will start the service again and it will continue generating the heartbeat events to the RN layer and we can see the *console.log* messages again. But for our surprise it does not happen. Frustrating right?

![Frustrating](https://thepracticaldev.s3.amazonaws.com/i/n804clzl8mx0o2i03tsb.gif)

When the device reboots and the broadcast message is sent, the service created in the the native layer gets up and start to send the events. However, there is no action to also gets up the RN layer to receive these events. In this moment we have a *NullPointerException* when the service tries to access a nonexistent React Context. To solve this problem it's time to use a great tool provided by the React API: Headless JS.

##Step 5 - Creating the Headless Service

A Headless JS is a RN service able to encapsulate some javascript operations and execute them detached from the application, like an android service. The headless service can do any kind of operation, except UI operations. In the actual example, the headless service can substitute the *RCTDeviceEventEmitter*, removing the direct use of React Context in the native layer.

Firstly, in the *HeartbeatService* class, we replace the event emitter with the headless service start, like below. When we do it, the service will execute the operation and it will go into a "paused" mode, until it is started again after two seconds. 

```java
public class HeartbeatService extends Service {
    ...
    private Handler handler = new Handler();
    private Runnable runnableCode = new Runnable() {
        @Override
        public void run() {
            // context.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("Heartbeat",null);
            Context context = getApplicationContext();
            Intent myIntent = new Intent(context, HeartbeatEventService.class);
            context.startService(myIntent);
            HeadlessJsTaskService.acquireWakeLockNow(context);
            handler.postDelayed(this, 2000);
        }
    };
    ...
}
```

Now we create the *HeartbeatEventService* like below. You can notice that we don't use the React Context, so the service has its own context. The name of the event in the settings must be the same defined before. 

```java
//HeartbeatEventService

public class HeartbeatEventService extends HeadlessJsTaskService {
    @Nullable
    protected HeadlessJsTaskConfig getTaskConfig(Intent intent) {
        Bundle extras = intent.getExtras();
        return new HeadlessJsTaskConfig(
                "Heartbeat",
                extras != null ? Arguments.fromBundle(extras) : null,
                5000,
                true);
    }
}
```

A headless service must be registered on [AppRegistry](https://facebook.github.io/react-native/docs/appregistry) and just as its documentation says, every app registry should be required early in the require sequence to make sure the JS execution environment is setup before other modules are required. In the *index.js* we call the registry like below.

```javascript
// index.js

AppRegistry.registerHeadlessTask('Heartbeat', () => MyHeadlessTask);
```
 
Now, the *MyHeadlessTask* is responsible to change the width and height of the heart image through a state. As we have here a centralized state shared with the App component, I decided to use [Redux](https://redux.js.org/) instead of hooks. With this, it's just necessary to create the [basic structure](https://github.com/mathias5r/rn-heartbeat/blob/master/store.js) of redux (action, reducer and store) to set properly the state. The *MyHeadlessTask* method is shown below.

```javascript
const MyHeadlessTask = async () => {
  console.log('Receiving HeartBeat!');
  store.dispatch(setHeartBeat(true));
  setTimeout(() => {
    store.dispatch(setHeartBeat(false));
  }, 1000);
};
```

When a heartbeat is fired, the state passed to the App changes, rerendering the whole component. If we test again with the reboot process we can see that even in this state the service is able to gets up and fires the event again. Oh yeah! That's how it's done.

![Done](https://thepracticaldev.s3.amazonaws.com/i/58wj9hwf6ln8pwhtijlo.jpeg)

## Conclusion

We have done so far an unstoppable service in React Native integrating a native android module and using some important tools like broadcast receivers, headless JS and much more. For future works, the challenge is to do the same for an iOS system that has some restrictions about to do tasks with the app closed or not started.

All the code of this example you can see in 
[mathias5r/rn-heartbeat](https://github.com/mathias5r/rn-heartbeat)