How to use MQTT with React Native?

MQTT is designed as an extremely lightweight publish/subscribe messaging transport protocol. Getting its recent fame for “Internet of Things” technology it is useful for connections with remote locations where a small code footprint is required and/or network bandwidth is at a premium.

React Native helps you create native mobile apps with the help of JavaScript only, which is supportable for both Android and iOS platforms and helps to save development costs and time.

This tutorial assumes that you already have at least a basic knowledge of React Native and that you are familiar with MQTT and its concepts, thus we will only concentrate here on how to integrate MQTT in our React Native app.

Setup

So lets init a new React Native project:

react-native init MqttTutorial

Now that we have our template app, what I like to do is to add in package.json scripts to run and build the app like this:

"scripts": {

"start": "node node_modules/react-native/local-cli/cli.js start",

"test": "jest",

"ios": "react-native run-ios --simulator='iPhone SE'",

"android": "react-native run-android",

"ios-big": "react-native run-ios",

"build-android": "cd android && ./gradlew assembleRelease"

},

Great, now we should have our app up and running! So let’s start!

Add MQTT library to your project

We will use the Eclipse Paho Javascript client to connect our app to a Mqtt Broker. The Paho project provides open-source implementation for the Mqtt protocol for various programming languages, in our case we will use the javascript browser client in React Native. It is pure javascript, so we don’t have to mess with the native code (yah!). N.B – The Paho JavaScript Client is an MQTT browser-based client library written in Javascript that uses WebSockets to connect to an MQTT Broker, so you have to make sure that the MQTT Broker you are trying to connect to has a port to connect via websockets!

So, first, let’s create a folder src/core/libraries/mqtt to our project structure, and add to it 2 files – mqtt.js and index.js.

In mqtt.js, we just copy the Paho Javascript client code from here.

This implementation needs access to local storage, otherwise it will throw an error, so in index.js, we will create in memory storage which is an object that has 3 properties – setItem, getItem and removeItem, and will add it to the global scope, so that Paho can access it. Now we are ready to export our React Native MQTT library.

So, src/core/libraries/mqtt/index.js looks like this:

Object.defineProperty(exports, '__esModule', { value: true });

require('./mqtt');

// Set up an in-memory alternative to global localStorage

const myStorage = {

setItem: (key, item) => {

myStorage[key] =item;

},

getItem:key=>myStorage[key],

removeItem:key=> {

deletemyStorage[key];

},

};

function init() {

global.localStorage=myStorage;

}

exports.default = init;

Great, now we have to create a Singleton Mqtt service in src/core/services/MqttService.js, which looks like this:

import { Alert } from 'react-native';

import init from '../mqttLib';

init();

class MqttService {

static instance=null;

static getInstance() {

if (!MqttService.instance) {

MqttService.instance=new MqttService();

}

return MqttService.instance;

}

constructor() {

const clientId='SomeId';

this.client=new Paho.MQTT.Client('ws://iot.eclipse.org:80/ws', clientId);

this.client.onMessageArrived=this.onMessageArrived;

this.callbacks= {};

this.onSuccessHandler=undefined;

this.onConnectionLostHandler=undefined;

this.isConnected=false;

}

connectClient= (onSuccessHandler, onConnectionLostHandler) => {

this.onSuccessHandler=onSuccessHandler;

this.onConnectionLostHandler=onConnectionLostHandler;

this.client.onConnectionLost= () => {

this.isConnected=false;

onConnectionLostHandler();

};

this.client.connect({

timeout:10,

onSuccess: () => {

this.isConnected=true;

onSuccessHandler();

},

useSSL:false,

onFailure:this.onFailure,

reconnect:true,

keepAliveInterval:20,

cleanSession:true,

});

};

onFailure= ({ errorMessage }) => {

console.info(errorMessage);

this.isConnected=false;

Alert.alert(

'Could not connect to MQTT',

[{ text: 'TRY AGAIN', onPress: () => this.connectClient(this.onSuccessHandler, this.onConnectionLostHandler) }],

{

cancelable:false,

},

);

};

onMessageArrived=message=> {

const { payloadString, topic } =message;

this.callbacks[topic](payloadString);

};

publishMessage= (topic, message) => {

if (!this.isConnected) {

console.info('not connected');

return;

}

this.client.publish(topic, message);

};

subscribe= (topic, callback) => {

if (!this.isConnected) {

console.info('not connected');

return;

}

this.callbacks[topic] =callback;

this.client.subscribe(topic);

};

unsubscribe=topic=> {

if (!this.isConnected) {

console.info('not connected');

return;

}

delete this.callbacks[topic];

this.client.unsubscribe(topic);

};

}

export default MqttService.getInstance();

What we have is a module that exports a static method getInstance of the class MqttService, which then creates a Singleton pattern and whenever the MqttService is imported the it either returns the existing instance or creates a new one, even if it does not exist.

In the constructor, we create our client, which connects to the websocket port of the public broker ‘iot.eclipse.org’.

This is a list of all available public brokers, and we are using one them to speed up the development on our client app, without the need to think also for a mqtt broker (at the moment). But you are free to use also your own mqtt broker, as long as it has websocket port configured.

this.callbacks is a useful topic/callback map for handling the received messages.

And this.client.connect() is the function, which lets us connect to the broker, passing to it a connect configuration. You can read more about the available config options here.

Ok, lets use our service now!

Connect to MQTT broker on componentDidMount

Let’s add a notification to show us if we are connected or not. Add the following code in src/core/components/OfflineNotification.js:

import React from 'react';

import { View, Text, Dimensions, StyleSheet } from 'react-native';

const { width } = Dimensions.get('window');

const styles = StyleSheet.create({

  offlineContainer: {

    backgroundColor: '#b52424',

    height: 30,

    justifyContent: 'center',

    alignItems: 'center',

    flexDirection: 'row',

    width,

    position: 'absolute',

    zIndex: 2000,

    bottom: 0,

  },

  offlineText: { color: '#fff' },

});

function MiniOfflineSign() {

  return (

    <View style={styles.offlineContainer}>

      <Text style={styles.offlineText}>Not connected to MQTT</Text>

    </View>

  );

}

export default MiniOfflineSign;

Than modify App.js to look like this:

import React, { Component } from "react";

import { Platform, StyleSheet, Text, View } from "react-native";

import MqttService from "./src/core/services/MqttService";

import OfflineNotification from './src/core/components/OfflineNotification';

const instructions = Platform.select({

  ios: "Press Cmd+R to reload,\n" + "Cmd+D or shake for dev menu",

  android:

    "Double tap R on your keyboard to reload,\n" +

    "Shake or press menu button for dev menu"

});

type Props = {};

export default class App extends Component<Props> {

  state = {

    isConnected: false

  }

  componentDidMount() {

    MqttService.connectClient(

      this.mqttSuccessHandler,

      this.mqttConnectionLostHandler

    );

  }

  mqttSuccessHandler = () => {

    console.info("connected to mqtt");

    this.setState({

      isConnected: true

    });

  };

  mqttConnectionLostHandler = () => {

    this.setState({

      isConnected: false

    });

  };

  render() {

    const {isConnected } = this.state;

    return (

      <View style={styles.container}>

        {!isConnected && <OfflineNotification />}

        <Text style={styles.welcome}>Welcome to React Native!</Text>

        <Text style={styles.instructions}>To get started, edit App.js</Text>

        <Text style={styles.instructions}>{instructions}</Text>

      </View>

    );

  }

}

const styles = StyleSheet.create({

  container: {

    flex: 1,

    justifyContent: "center",

    alignItems: "center",

    backgroundColor: "#F5FCFF"

  },

  welcome: {

    fontSize: 20,

    textAlign: "center",

    margin: 10

  },

  instructions: {

    textAlign: "center",

    color: "#333333",

    marginBottom: 5

  }

});

Now, when refreshing, you should see for a some seconds a notification that you are currently not connected, and after that it will disappear. Hurray!

Subscribing and publishing to topics

First, you should download a desktop mqtt client, to test publishing and subscribing to topics. I am using Mqtt.fx, you can download it for your platform clicking the link.

First, let’s make our React Native app listen for messages on the WORLD topic.

In App.js, add a handler for WORLD topic messages (N.B – topics are case sensitive), and mqttSuccessHandler subscribe to WORLD topic with this handler as a callback. App.js should look now like this:

import React, { Component } from "react";

import { Platform, StyleSheet, Text, View } from "react-native";

import MqttService from "./src/core/services/MqttService";

import OfflineNotification from './src/core/components/OfflineNotification';

const instructions = Platform.select({

  ios: "Press Cmd+R to reload,\n" + "Cmd+D or shake for dev menu",

  android:

    "Double tap R on your keyboard to reload,\n" +

    "Shake or press menu button for dev menu"

});

type Props = {};

export default class App extends Component<Props> {

  state = {

    isConnected: false,

    message: ''

  }

  componentDidMount() {

    MqttService.connectClient(

      this.mqttSuccessHandler,

      this.mqttConnectionLostHandler

    );

  }

  onWORLD = message => {

    this.setState({

      message,

    })

  }

  mqttSuccessHandler = () => {

    console.info("connected to mqtt");

    MqttService.subscribe('WORLD', this.onWORLD)

    this.setState({

      isConnected: true

    });

  };

  mqttConnectionLostHandler = () => {

    this.setState({

      isConnected: false

    });

  };

  render() {

    const {isConnected, message } = this.state;

    return (

      <View style={styles.container}>

        {!isConnected && <OfflineNotification />}

        <Text style={styles.welcome}>You received message: {message}</Text>

      </View>

    );

  }

}

const styles = StyleSheet.create({

  container: {

    flex: 1,

    justifyContent: "center",

    alignItems: "center",

    backgroundColor: "#F5FCFF"

  },

  welcome: {

    fontSize: 20,

    textAlign: "center",

    margin: 10

  },

  instructions: {

    textAlign: "center",

    color: "#333333",

    marginBottom: 5

  }

});


For publishing a message, I will demonstrate with a button, which on click publishes hardcoded “Hello from the app” text to TestPublish topic.

So now, modify App.js to look like this:

import React, { Component } from "react";

import { Platform, StyleSheet, Text, View, Button } from "react-native";

import MqttService from "./src/core/services/MqttService";

import OfflineNotification from "./src/core/components/OfflineNotification";

const instructions = Platform.select({

ios:"Press Cmd+R to reload,\n"+"Cmd+D or shake for dev menu",

android:

"Double tap R on your keyboard to reload,\n"+

"Shake or press menu button for dev menu"

});

type Props = {};

export default class App extends Component<Props> {

state= {

isConnected:false,

message:""

};

componentDidMount() {

MqttService.connectClient(

this.mqttSuccessHandler,

this.mqttConnectionLostHandler

);

}

onWORLD=message=> {

this.setState({

message

});

};

mqttSuccessHandler= () => {

console.info("connected to mqtt");

MqttService.subscribe("WORLD", this.onWORLD);

this.setState({

isConnected:true

});

};

mqttConnectionLostHandler= () => {

this.setState({

isConnected:false

});

};

onPublish= () => {

MqttService.publishMessage("TestPublish", "Hello from the app");

}

render() {

const { isConnected, message } =this.state;

return (

<Viewstyle={styles.container}>

{!isConnected && <OfflineNotification/>}

<Textstyle={styles.welcome}>You received message: {message}</Text>

<Button

onPress={this.onPublish}

title="Publish"

color="#841584"

/>

</View>

);

}

}

const styles = StyleSheet.create({

container: {

flex:1,

justifyContent:"center",

alignItems:"center",

backgroundColor:"#F5FCFF"

},

welcome: {

fontSize:20,

textAlign:"center",

margin:10

},

instructions: {

textAlign:"center",

color:"#333333",

marginBottom:5

}

});
And voila! 🙂 Now you are all set to explore the possibilities which MQTT and React Native give you!
You can find the complete code in this repo.

x

Motion Software starts operating under the name of its parent company Exadel, taking effect on July 15th.

More Info

Motion Software uses cookies to improve site functionality, provide you with a better browsing experience, and to enable our partners to advertise to you. Detailed information on the use of cookies on this Site, and how you can decline them, is provided in our Cookie Policy Learn more about cookies, Opens in new tab. By using this Site or clicking on OK, you consent to the use of cookies.

OK