XMPP real-time chat in React Native

Here we are going to explain how to use XMPP protocol for real-time chat in React Native apps.

Create React Native App

To create a React Native app — use the Getting Started guide for reference:

npm install -g create-react-native-app
create-react-native-app AwesomeProject 
cd AwesomeProject 
npm start

So we have a skeleton project and now we can add an XMPP library dependency into it.

Add XMPP lib depdendency

Here we are going to use xmpp.js lib since the same code base can work on multiple environments — Node.js, React Native, Native Script.

The npm package of this lib is not updated properly (last update published a year ago), so we are forced to use the latest master code which is actually the most stable version of the lib:

git clone git@github.com:xmppjs/xmpp.js.git
cd xmpp.js
make

Prepare App UI

Our app will have 2 buttons: to connect to XMPP server and to send a message. Also it will contain a text view to which we will post statuses about connection and messages.

Here is the whole content of our skeleton App.js file:

import React from 'react';
import { StyleSheet, Text, TouchableHighlight, View, ScrollView } from 'react-native';
export default class App extends React.Component {
constructor(props) {
super(props);
    this.state = {
output: ''
}
}
  onStartConnect() {
  }
  onSendMessage() {
  }
  render() {
    var buttons = (
<View style={styles.container}>
<TouchableHighlight
onPress={this.onStartConnect.bind(this)}
style={styles.button}>
<Text style={styles.buttonText}>
Connect to XMPP server (login)
</Text>
</TouchableHighlight>
<TouchableHighlight
onPress={this.onSendMessage.bind(this)}
style={styles.button}>
<Text style={styles.buttonText}>
Send a message
</Text>
</TouchableHighlight>
</View>
);
    return (
<View style={styles.container}>
<Text style={styles.output_result}>
{this.state.output}
</Text>
{buttons}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
button: {
height: 50,
backgroundColor: '#48BBEC',
alignSelf: 'stretch',
marginTop: 10,
justifyContent: 'center',
},
buttonText: {
fontSize: 22,
color: '#FFF',
alignSelf: 'center'
},
output_result: {
color: '#000',
marginTop: 20,
}
});

Initialise XMPP client

Now open App.js file and initialise an XMPP client:

var client = require('./xmpp.js/packages/client');

Also we need to connect a base-64 dependency since this lib uses it inside:

In your package.js do the following:

"dependencies": {

"base-64": "0.1.0"
}

Then do npm install in terminal.

Then add the following code in your App.js:

var base64 = require('base-64');
global.btoa = base64.encode;
global.atob = base64.decode;

Implement the ‘Connect to Server’ logic

Modify a constructor and add the following code:

constructor(props) {
super(props);
  this.state = {
output: ''
}
  this.xmppClientListeners = [];
this.xmppClient = XMPP.xmpp().client;
  // you XMPP server endpoints
//
this.XMPPServerOptions = {uri: 'wss://chat.connectycube.com:5291',
domain: 'chat.connectycube.com'};
  // Demo user credentials (25045–19@chat.connectycube.com)
//
this.XMPPUserCredentials = {jidLocalPart: '25045–19',
password: 'securepwd123'};
}

Here we initialise an xmppClient and also setup XMPP server endpoint and a demo user credentials.

Next, we implement a connect method which will initiate a connection to XMPP server with above demo user:

connect(options){
this.xmppClient.start(options);
}

Next, implement an addListeners method that will setup all needed connection callbacks e.g. for success connect, for incoming messages etc.:

addListeners() {
var self = this;
    var removeAllListeners = function(){
self.xmppClientListeners.forEach(function(listener){
self.xmppClient.removeListener(listener.name,
listener.callback);
});
self.xmppClientListeners = [];
}
    removeAllListeners();
    const callbackConnect = function() {
self.log('CONNECTING');
};
this.xmppClient.on('connect', callbackConnect);
this.xmppClientListeners.push({name: 'connect',
callback: callbackConnect});
    const callbackOnline = function(jid) {
self.log('ONLINE');
};
this.xmppClient.on('online', callbackOnline);
this.xmppClientListeners.push({name: 'online',
callback: callbackOnline});
    const callbackStatus = function(status, value) {
// self.log('status: ' + status);
};
this.xmppClient.on('status', callbackStatus);
this.xmppClientListeners.push({name: 'status',
callback: callbackStatus});
    // this.xmppClientReconnect.on('reconnecting', function() {
// Utils.DLog('[Chat]', 'RECONNECTING');
// });
//
// this.xmppClientReconnect.on('reconnected', function() {
// Utils.DLog('[Chat]', 'RECONNECTED');
// });
    const callbackStanza = function(stanza) {
// console.log('stanza', stanza.toString())
// after 'input' and 'element' (only if stanza, not nonza)
      if (stanza.is('presence')) {
self.log("On PRESENCE: " + stanza);
} else if (stanza.is('iq')) {
self.log("On IQ: " + stanza);
} else if(stanza.is('message')) {
self.log("On MESSAGE: " + stanza);
}
};
this.xmppClient.on('stanza', callbackStanza);
this.xmppClientListeners.push({name: 'stanza',
callback: callbackStanza});
    const callbackError = function(err) {
self.log('ERROR:', err);
};
this.xmppClient.on('error', callbackError);
this.xmppClientListeners.push({name: 'error',
callback: callbackError});
    // this.xmppClient.on('element', function(element) {
// // console.log('element', element.toString())
// // after 'input'
// });
    // this.xmppClient.on('send', function(element) {
// // console.log('send', element.toString())
// // after write to socket
// });
    // this.xmppClient.on('outgoing', function(element) {
// // before send
// // console.log('outgoing', element.toString())
// });
    const callbackOutput = function(str) {
// self.log('SENT:', str);
};
this.xmppClient.on('output', callbackOutput);
this.xmppClientListeners.push({name: 'output',
callback: callbackOutput});
    const callbackInput = function(str) {
// self.log('RECV:', str);
};
this.xmppClient.on('input', callbackInput);
this.xmppClientListeners.push({name: 'input',
callback: callbackInput});
    const callbackAuthenticate = function(authenticate) {
self.log('AUTHENTICATING');
      return authenticate(self.XMPPUserCredentials.jidLocalPart,
self.XMPPUserCredentials.password)
};
this.xmppClient.handle('authenticate', callbackAuthenticate);
this.xmppClientListeners.push({name: 'authenticate',
callback: callbackAuthenticate});
}
log(text){
console.log(text);
    this.setState({output: this.state.output + "\n" + text})
}

And finally we can implement an onStartConnect button callback where we can initiate a connection & authorisation process with the XMPP server:

onStartConnect() {
this.addListeners();
  this.connect(this.XMPPServerOptions);
}

Now you can run the app, press on Connect to XMPP server (login) button and check it. You should see something like this:

Demo of XMPP login to XMPP server

Implement ‘Send a Message’ functionality

Now we will implement an onSendMessage method which will build a message and send it to current user:

onSendMessage() {
// he we send a message for the same user
  var stanzaParams = {
from: this.XMPPUserCredentials.jidLocalPart + "@" +
this.XMPPServerOptions.domain,
to: this.XMPPUserCredentials.jidLocalPart + "@" +
this.XMPPServerOptions.domain,
type: ‘chat’,
id: Math.floor(Math.random() * Math.floor(999999999))
};
var messageStanza = XMPP.xml("message", stanzaParams);
  messageStanza.c('body', {
xmlns: 'jabber:client',
}).t("Hello Amigo").up();
  this.xmppClient.send(messageStanza);
}

Then you will receive the message using above callback methods.

Conclusion

The complete source code of the app is located at GitHub repo https://github.com/ConnectyCube/react-native-xmpp-demo

Need a complete cross-platform real-time Chat app?

ConnectyCube provides a JavaScript SDK for real-time messaging and video calling apps which works across Browser, React Native, Native Script and Node.js environments.

All the modern Chat features are supported:

  • 1–1 messaging
  • Group messaging
  • Cross-platform
  • Sent/Delivered/Read statuses
  • ‘Is typing’ statuses
  • File attachments
  • Automatic push notifications to offline users
  • Contact list
  • Black list
  • End-to-end Encryption via additional plugins
  • Chat moderation (via Trust & Safety (TnS) feature)

Sign Up today