Add In-App Messaging to Your Mobile App – React Native / Expo

Eze S.
Eze S.
Published March 19, 2020 Updated May 12, 2020

Stream's Messaging API allows you to build real-time chat applications that are scalable, fault-tolerant, secure, and fast, so you don’t have to re-invent the wheel by starting from scratch. You’ll take less time to create a robust app (like days to create a real-time chat application with Stream instead of months)!.

By the end of this tutorial, you should have a functional chat application with in-app messaging. In-app messaging allows you to engage users who are actively using your mobile app by sending them content that will encourage them to take action or keep them informed.

Let's create a chat app to which we’ll add in-app messaging. We'll also want our app to send an in-app message to everyone in the chat group when someone sends a message to the group.

Prerequisites

To follow along with this post, ensure sure that you’ve installed the following:

Note that you’ll need a macOS, with XCode installed to run the iOS emulator.

React Native is a mobile app application development framework that allows you to build a multi-platform mobile application — Android and iOS.

That means at the end of this tutorial; you will have an app with in-app messaging that you can deploy for both android and iOS devices.

Setting Up

First of all, let’s set up a react native application with Expo. Run the following command to install expo-cli:

sh
1
$ npm install -g expo-cli

Then, run the following command to create a project and install all the dependencies required for Stream to work with React Native and Expo projects:

sh
1
2
3
4
5
$ expo init -t blank --name cool-chat-app && cd cool-chat-app $ yarn add stream-chat-expo react-navigation@4.1.0 react-navigation-stack@2.1.0 $ expo install @react-native-community/netinfo@4.6.0 react-native-gesture-handler@1.5.6 react-native-reanimated@1.4.0 react-native-screens@2.0.0-alpha.12 react-native-safe-area-context@0.6.0 @react-native-community/masked-view@0.1.5 react-native-in-app-notification metro-react-native-babel-preset

Once those are installed, you can use the following command to create a components directory (where we’ll put all our components) and a Chat.js component file within it:

sh
1
mkdir components && touch components/Chat.js

Your app structure should look like this after running the command above:

.
├── App.js
├── app.json
├── assets
│   ├── icon.png
│   └── splash.png
├── babel.config.js
├── components
│   └── Chat.js
├── package.json
├── web-build
│   └── register-service-worker.js
└── yarn.lock

Next up, let’s add Stream Chat to the app!

Registering on the Stream Website

Setting up a Stream Chat account is simple — head over to the Stream website and register with your Github account or with your email address.

Stream Chat - Get Started

Once your registration is complete, head over to your dashboard, where you will find your API credentials (API_KEY, SECRET and APP_ID), as shown in the image below:

Stream Chat - Dashboard

Keep this information in a secure place; you’ll need it to authenticate with the Stream API/SDK as we proceed.

Getting Started

Let’s get into the code!

Create a .env file in the root of the directory and add the APP_KEY you got from the dashboard:

API_KEY=<YOUR_API_KEY>

Open your ./babel.config.js/ and add the code below to the presets:

'module:metro-react-native-babel-preset',
'module:react-native-dotenv',

Doing so will allow us to import our environment variables from the .env file:

module.exports = function(api) {
  api.cache(true);

  return {
    presets: [
      'babel-preset-expo',
      'module:metro-react-native-babel-preset',
      'module:react-native-dotenv'
    ]
  };
};

Open the /Component/Chat.js file we created initially, and add the following content to it:

import React, { Component } from 'react';
import { View, Text, StyleSheet, SafeAreaView } from 'react-native';
import { withInAppNotification } from 'react-native-in-app-notification';
import { API_KEY } from 'react-native-dotenv';
import { StreamChat } from 'stream-chat';
import { Chat, Channel, MessageList, MessageInput } from 'stream-chat-expo';

const chatClient = new StreamChat(API_KEY);
const userToken = API_TOKEN;
const user = {
  id: 'green-heart-8',
  name: 'Green heart',
  image:
    'https://stepupandlive.files.wordpress.com/2014/09/3d-animated-frog-image.jpg'
};

chatClient.setUser(user, userToken);

class ChatScreen extends Component {
  render() {
    const channel = chatClient.channel('messaging', 'green-heart-8');
    channel.watch();

    channel.on('message.new', event => {
      const message = channel.state.messages[channel.state.messages.length - 1];

      if (message.user.id !== chatClient.user.id) {
        this.props.showNotification({
          title: 'Stream Notification',
          message: `${message.user.name} says: ${message.text}`
        });
      }
    });

    return (
      <SafeAreaView>
        <Chat client={chatClient}>
          <Channel channel={channel}>
            <View style={{ display: 'flex', height: '100%' }}>
              <MessageList />
              <MessageInput />
            </View>
          </Channel>
        </Chat>
      </SafeAreaView>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  }
});

export default withInAppNotification(ChatScreen);

Let’s explain what is going on here...

Building your own app? Get early access to our Livestream or Video Calling API and launch in days!

Here, we import the in-app messaging notification package we intend to use to show the app messaging:

import { withInAppNotification } from 'react-native-in-app-notification';

Then, we import Stream and the Stream Chat Components we want to use for this app:

import { StreamChat } from 'stream-chat';
import { Chat, Channel, MessageList, MessageInput } from 'stream-chat-expo';

Next, we initialize a new Stream Client, and then set a user:

const chatClient = new StreamChat(API_KEY);
const userToken = API_TOKEN; // you can retrieve this from the backend server

const user = {
  id: 'green-heart-8',
  name: 'Green heart',
  image:
    'https://stepupandlive.files.wordpress.com/2014/09/3d-animated-frog-image.jpg'
};

chatClient.setUser(user, userToken);

You’ll need to retrieve the token from an API endpoint; you can check out this open-source API for Stream that you can use right off the bat to get authenticated!

All you need to do is clone the repo:

sh
1
$ git clone https://github.com/astrotars/stream-chat-api.git

run the command:

sh
1
$ npm install

Then, add your API KEY and API SECRET to the .env file of the project and you can send a post request with the details of the user you want to authenticate as a JSON object to the endpoint http://localhost:8080/v1/auth/init, like so:

{
  "name": {
          "first": "First Name",
          "last": "Last Name"
  },
  "email": "foo@bar.baz",
  "password": "qux"
}

This should return to you a token, which you can use to set the User. You can generate this token like in a login page:

chatClient.setUser(user, userToken);

Then, in the ChatScreen component’s render method, create a channel with the type "messaging" and give it any title you'd like; we’ll call ours golf-club. Next, call the watch() method on the channel client so that you can monitor the activities on the channel:

const channel = chatClient.channel('messaging', 'golf-club');
channel.watch();

In the following section, we subscribe to the channel’s new message event, then check if the message is not from you. If that’s true, we show a notification, using the props from the react-native-in-app-messaging package (the title of the message and the actual message body).

channel.on('message.new', event => {
  const message = channel.state.messages[channel.state.messages.length - 1];

  if (message.user.id !== chatClient.user.id) {
    this.props.showNotification({
      title: 'Stream Notification',
      message: `${message.user.name} says: ${message.text}`
    });
  }
});

Notice we are not sending the in-app message to ourself, because it doesn’t make sense to send a notification to ourselves when we send a message.

Right here:

const message = channel.state.messages[channel.state.messages.length - 1];

We are getting the last message object that was sent to the channel, and broadcasting it to every member of the channel as an "in-app message".

To get the in-app messaging plugin to work correctly with our app, let’s wrap our component with the withInAppNotification HOC we imported initially, like so:

export default withInAppNotification(ChatScreen);

Also, we need to add it to our app component in the App.js file:

import React, { Component } from 'react';
import { InAppNotificationProvider } from 'react-native-in-app-notification';
import Chat from './components/chat';

export default class App extends Component {
  render() {
    return (
      <InAppNotificationProvider>
        <Chat />
      </InAppNotificationProvider>
    );
  }
}

Finally, let’s return the Stream Chat components, as shown below:

return (
  <SafeAreaView>
    <Chat client={chatClient}>
      <Channel channel={channel}>
        <View style={{ display: 'flex', height: '100%' }}>
          <MessageList />
          <MessageInput />
        </View>
      </Channel>
    </Chat>
  </SafeAreaView>
);

This is all we need to get our app with in-app messaging working!

Here is a demo of what we’ve built so far:

React Native - Expo Example

Wrapping Up

There is so much you can do with Stream Chat! I encourage you to look at the docs to find more amazing features of Stream Chat that you can add to the app.

We'll be excited to see what you’ll build with Stream Chat!

Looking for the complete source code? It’s on GitHub!

Happy coding!

Integrating Video With Your App?
We've built a Video and Audio solution just for you. Check out our APIs and SDKs.
Learn more ->