Build a Chatbot in React Native with Syncano (iOS & Android)

Daniel SiwekDaniel Siwek

Build a chatbot in React Native with push notifications for iOS and Android devices. Thanks to Syncano, it's really simple. Create your chatbot now!

You most likely use some kind of messenger or chat application every day. Have you ever thought about creating a mobile chatbot application that looks and feels exactly like these messengers? In this tutorial, users will send messages to our React Native chatbot, which will recognize specific keywords and deliver the appropriate response.

For this project, we will also implement the Push Notifications Socket from Syncano, which will send notifications to all devices where your application has been installed.

What’s more, we will create one application that will be ready to use on both the iOS and Android platforms, all thanks to React Native.

In this application, a user can ask about anything, and the chatbot will respond based on the keyword recognition. In our example, the chatbot gets its answers from Syncano Documentation and API References. So, you can ask, for example:

How can I create a Class in JavaScript?

And the chatbot will respond with the proper answer or information! For simplification, users will be able to see their conversation history. Users will also be stored in Syncano to allow for sending push notifications.

For simplicity's sake, we’re going to create a Schedule that sends push notifications at a specific time, for example, a weekly reminder from our chatbot. This functionality can, of course, be improved to send push notifications for each new message, just like a standard messenger.

First, let’s talk about some of the helpers we are going to be using. The most important will be React Native, our framework of choice for building native apps across multiple platforms. Secondly, of course, we will need Syncano as our backend service. For faster development, we will also bring into play a library named GiftedChat for React Native. This library will save us time that we usually spend creating views, and allow us to focus only on the logic and the integration of our application with Syncano.

This tutorial will guide you through all the steps, from setting up a Syncano Instance, to writing the logic of your application in React Native, to running your chatbot on your device.

But, if you want see results before building your own custom application, please visit the GitHub Project Page.
For Android platforms, you’ll be able to download the .apk file and install it on your device. If you’re using an iOS device, you’ll need to download the repository listed above and either download it to your device via USB or run it using an emulator via Xcode.

Step 1: Setting Up Syncano

First things first, please make sure you have signed up for a Syncano account. Next, we need to create the structure of each message object on Syncano.

In Syncano, each Data Object inherits the “blueprint” of its Data Class, so let’s create our Data Class now.

You can create it using our Dashboard interface or by using our API. In this article, we will show you how do that using your Syncano Dashboard.

Create a Class for Messages

Messages class on Syncano

Just a note on Data Classes. The schema is the configuration of the fields or properties that each Data Object attached to it will inherit. This means, for example, that each message that is created will have text, user, and image fields.

Next we’ll set up the push notifications for this chatbot!

Add Config to Push Notifications

The process of configuring a Push Notification Socket looks different for each of the platforms. For the full tutorial on how to configure this properly, I will refer you to our Documentation, where it is explained step by step.

Android - GCM Socket Configuration

iOS - APNs Socket Configuration

Note: In our application, we will need the Sender ID from your app in the Google Developers Console, so be sure that you have completed both of these steps.

These notifications can’t send themselves! So next we’ll be setting up the Script that processes the message and sends the notification!

Create a Script for Sending Notifications

After you have created the Script, you can write the following code inside the Code Editor.

Sample code:
var Syncano = require("syncano");  
var _ = require("lodash");

var connection = Syncano({  
    apiKey: '<YOUR_API_KEY>',
    defaults: {
      instanceName: '<YOUR_INSTANCE_NAME>'
  }
});

var sampleMessages = [  
    "Hello, how are you?",
    "Do you remember me?",
    "Ask me something about Syncano",
    "Syncano is the best! :)"
];

var randomMessage = _.sample(sampleMessages);

var GCMDevice = connection.GCMDevice;  
var GCMMessage = connection.GCMMessage;

var APNSDevice = connection.APNSDevice;  
var APNSMessage = connection.APNSMessage;

GCMDevice.please().list().then(function(devices) {  
    var registration_ids = _.map(devices, (device) => device.registration_id);
    var content = {
            registration_ids,
            environment: 'development',
            data: {message: randomMessage}
    };

    GCMMessage.please().create({content}).then(function(message) {
        console.log('Android Message sent:', message.content.data.message);
    });
});

APNSDevice.please().list().then(function(devices) {  
    var registration_ids = _.map(devices, (device) => device.registration_id);
    var content = {
            registration_ids,
            environment: 'development',
            aps: {alert: randomMessage}
    };
    APNSMessage.please().create({content}).then(function(message) 
        console.log('iOS Message sent:', message.content.aps.alert);
    });
});

Whenever you run this Script, a notification will be sent to every user’s device that has downloaded your chatbot. Awesome, right?

Configure Schedule for Regular Notifications

Now, we can create a Schedule for our new Script. This will allow us to send push notifications regularly to our devices. For example, every Monday we could send a motivational notification, encouraging users to talk with our chatbot or ask it questions.

Create your Chatbot Step by Step

If you don't want to make this application from scratch, you can go to the GitHub Project Page, download the ready-made project, and just connect it to your Instance on Syncano.

First, I will refer you to the React Native documentation so you can look at the Getting Started Section. It explains the basic installation of the React Native CLI. This will allow us to create our first project in React Native. As it says in the documentation, You will need Xcode, Node.js, the React Native command line tools, and Watchman. So, be sure that you have all of them.

Dependencies

Next, we have to install all the dependencies we need for our project. Make sure your dependencies in your package.json look like this:

  "dependencies": {
    "lodash": "4.15.0",
    "react": "15.3.1",
    "react-native": "0.33.0",
    "react-native-gifted-chat": "0.0.10",
    "react-native-push-notification": "2.1.0",
    "react-native-system-notification": "0.1.11",
    "syncano": "1.0.26"
  },
  "devDependencies": {
    "babel-plugin-add-module-exports": "0.2.1",
    "babel-plugin-lodash": "^3.2.8",
    "babel-plugin-transform-inline-environment-variables": "6.8.0",
    "babel-preset-es2015": "6.14.0",
    "babel-preset-react-native": "1.9.0"
  }

After that, run the command npm install in your project folder.

Using the Same Code for Both Platforms

To use this same code on both platforms, we will use a little trick.

Fill both your index.ios.js and index.android.js files with this code:

import {  
  AppRegistry,
} from 'react-native';

import App from './App';

AppRegistry.registerComponent('chatbotSyncano', () => App);  

By doing this, our application will use the App file as the main component for both platforms. Now, we need to create a file named App.js in the main folder of our project.

You can see a full preview of this file on GitHub, so for this tutorial I will just explain to you what's going on.

Main Component

First of all, on the component constructor, we have to define our initial state and bind all methods for proper context.

  constructor(props) {
    super(props);
    this.state = {
      messages: [],
      nextPage: null,
      hasNextPage: true,
      typingText: null,
      isLoadingEarlier: false,
    };

    this._isMounted = false;
    this.onSend = this.onSend.bind(this);
    this.onReceive = this.onReceive.bind(this);
    this.renderFooter = this.renderFooter.bind(this);
    this.onLoadEarlier = this.onLoadEarlier.bind(this);
    this.setOldMessages = this.setOldMessages.bind(this);
  }

What Do All of These Methods Do?

this.onSend()

This is the method that calls whenever a user types and sends a message to our chatbot. Tasks for this function are

this.onReceive()

This function first prepares the answer from the chatbot, then saves it to the state and sends it to Syncano. In this method, our logic associated with answering ends, so we set the state of typingText: null to stop displaying the footer that shows the bot is still typing.

this.onLoadEarlier()

Here, we check to see if there are more messages than we have actually received. This function is called whenever a user clicks the button to load more messages. Of course, on the first call using this method, we don't have a this.state.nextPage so we call the getMessages() function from the API. This call is responsible for getting the first 10 messages from history.

In most chat applications, we would most likely have more than 10 messages. So, in the second, and each following click on the button, we would probably have next page shown. For that to happen, we call another method from our imported API methods named loadMoreMessages(). This function loads more messages from Syncano, and returns them. This will give us the “next page” for our Data Objects. We can specifically define how many messages should be returned on each call using this function by setting a parameter - pageSize() - in our call to Syncano.

As a callback to these API methods, we have named this same function setOldMessages().

this.setOldMessages()

Here, we are not doing anything special, we are just picking up parameters that are returned from our API functions and setting these into our storage for later use in our application lifecycle.

this.renderFooter()

This function sends a View to the GiftedChat component if the chatbot is typing. We can use this function to show info about the state of typing the chatbot currently has. We check to see if the chatbot is actually writing and, if it's true, return the styled popup that will be rendered by the GiftedChat component in the correct place.

Methods for Answer Logic:

this.answerDocs()

Here, the message the user has sent is prepared by removing unnecessary characters. For example, in this function, we get rid of all special characters, such as question marks or exclamation points. They are unnecessary for our chatbot. Due to the fact that answers from our chatbot are sections of text pulled from Syncano Documentation and API references, we have to distinguish, for example, whether a user is asking about Script or Script Endpoint. Next, we call setAnswer() to search for the correct answer to the user’s inquiry. Then, we save it to a variable and transfer it to the last step of the chatbot’s response.

this.setAnswer()

In the previous method, we prepared our user’s message. Here, we will prepare the answer message. First, we call the mapDictionary() helper, where the greater part of our magic-logic happens. Next, we set a custom answer, which will be sent to the user if the inquiry was not precise enough. We also assume that the chatbot response could contain an image. If there is no image and the response is still an object, that means the inquiry was not precise enough. A successful case will return the correct answer to the setAnswer() method.

this.mapDictionary()

First, we define our temporary answer as a large object with all of our possible responses. Next, we convert all keys from the current object into an array. Then, by multiplying the number of keys from this array by the length of our array with each word sent from the user, we can be confident that each word will be tested with all of our possible responses. Then, we use our helper, where we define which words are associated with which responses. For example, if a user asks about scripts it should lead to the same response as just script. This is the same for js => javascript or add => create. In the end, we simply return the closest related answer.

Data for Chatbot Answers

In our root directory, we created a folder named data where we will create responses for our chatbot. We can divide the responses according to the type of Syncano feature by creating separate files for each feature-related response. For this tutorial, we divided it by each Socket. We also added some standard responses for messages like hi or welcome. Next, we should create a help command for our users. When asked, our chatbot will give examples of how to ask it questions.

We linked all of our possible answers in one file named dictionary.js. Here is where we import all of our files with answers to keep things clean. We also include our helper, which defines which words should be connected to which answers.

Save Devices to Send Them Notifications

If we want to send notifications to a user’s device, we have to register their device ID. For that, we will use the react-native-push-notification library. If you followed the beginning of this tutorial, you should have this library installed.

Get the Registration ID

Next, as the documentation of this library says, we have to properly configure Push Notifications to get the registration ID from the user’s device. Paste this code in your App.js file just under your imports:

PushNotification.configure({  
    onRegister: function(token) {
      console.log(token);
      ActionsDevices.addDevice(token);
    },
    onNotification: function(notification) {
        console.log( 'NOTIFICATION::', notification );
    }, 
    senderID: "<YOUR_SENDER_ID>",
    permissions: {
        alert: true,
        badge: true,
        sound: true
    },
    popInitialNotification: true,
    requestPermissions: false,
});
PushNotification.requestPermissions();  

As you see, you will need your sender ID from your app in the Google Developers Console. If you don't know how to get this ID, take a look at the Syncano Documentation for it: Create your app in Google Developers Console

After configuring this library, we also have to install it on the Android and iOS platforms. To do that, I recommend you read the README for this library:
iOS Instructions and Android Instructions.

Save the Device on Syncano

We also use this configuration to save the device to Syncano whenever a user launches your application on their device. We call ActionsDevices.addDevice(token), which we defined in our API file. As a parameter, we pass token which is the object with the registration ID and operating system of the user’s device.
So, let's look at this method in our API file:

  addDevice: ({ token, os }) => {
    const device = {
      label:"DEVICE_NAME",
      registration_id: token
    };
    console.log(os);

    os === 'android' && GCMDevice.please().list().then((devices) => {
      console.log('Android Devices::', devices);
      const isDevice = _.find(devices, { registration_id: token });

      !isDevice && GCMDevice.please().create(device).then((device) => {
        console.log('Android Device::', device);
      });
    });

    os === 'ios' && APNSDevice.please().list().then((devices) => {
      console.log('iOS Devices::', devices);
      const isDevice = _.find(devices, { registration_id: token });

      !isDevice && APNSDevice.please().create(device).then((device) => {
        console.log('iOS Device::', device);
      });
    });
  }

First, our passed token is an object with two keys: registration ID and operating system. Here’s a little destructuring trick. Instead of passing just the token and then getting each variable like this: token.token and token.os, we can instead use destructuring and use the ({ token, os }) notation. Now we have two variables: the registration ID of the user’s device, and his operating system. Based on the OS, we can make the proper call to Syncano for either iOS or Android devices. Of course, first we have to check and see if the current device is already saved in Syncano. To do that, we need to list all of the registered devices and try to find the current user’s device. If we don't find it, we can save the device as a new device.

How to Run Chatbot on Your Device

Running a React Native application is described very clearly in the official documentation for React Native, so I would suggest reading through that. You can find how to run your project on Android here and iOS here.

We can also run it on a device emulator. To do that for iOS, run your Xcode project, which you can find in the ios folder in your project root directory. Then just click Run and wait until your app builds.

screen-how-to-run-ios-emulator

You can use Genymotion, the Android emulator, to test the Android version of your application. Here’s the official documentation on how to do that.

Improving Your Mobile Application

Your application can always be better, and below we give you some ideas!

Real-time Data with Channels

Real-time Channels allow you to be able to create a chat in real time. For this example, it’s more useful when you want to change your chatbot to real people. It allows them to get new messages without refreshing their application.

Users and Groups

You can also implement Users & Groups to include login and registration functionality in your chat. It gives you the ability to load the message history of only the current user who is actually logged in. Secondly, you would be able to create Groups that specific Users belong to, determining their permissions on your Data Objects.

Triggers for notifications whenever you teach your bot new answers.

If you move all your chatbot answers to a new Data Class, you can use a Trigger to notify your users whenever you add new answers. For example, if you teach your chatbot answers from the computer games domain, then the Trigger will send notifications to all of your users saying something like: Hi, now you can ask me about the computer games domain!

Conclusion

In this tutorial, you learned how simple it is to build a mobile application for iOS and Android platforms with push notifications using React Native and Syncano. Now you are able to send notifications to all of the devices that have downloaded and launched your chatbot. Use that to remind your users about your application and to send information about new features that you create. Let us know what you think about this tutorial on Twitter by tweeting @Syncano !

Also, feel free to ask any questions you have in the comments under this post, by joining our Slack community channel, or by writing to our support team at [email protected]. Good luck!

Build powerful apps in half the time

Use our serverless platform to set up your backend in minutes.

Learn more
Daniel Siwek
Author

Daniel Siwek