React Native Cross-Platform Chat App with PubNub SDK
Build a seamless React Native chat app with PubNub SDK. Support group chats, presence indicators, and more—cross-platform for iOS & Android
Build a Chat App with PubNub's CORE SDK for React Native
When developing an application with chat, React Native allows you to develop for both Android and iOS from a single code base.
This React Native chat app tutorial will walk you through developing a React Native chat app using the PubNub React and Javascript SDKs with the following features:
Messaging and chat bubbles: Group chat with everyone in the same room
Presence indicators for participants when they join or leave the room
Load historical messages sent or received before you joined the room
Customize your name
Messages are timestamped
Runs on Android and iOS from the same codebase
The source code for this application can be found on Github at https://github.com/PubNubDevelopers/GettingStarted-ReactNative-SDK-Tutorial
This is a Getting Started tutorial and only scratches the surface of what you can achieve with the PubNub SDK. See our other tutorials to add features like whiteboards, 1:1 chat, message reactions, push notifications or location tracking.
Why Build a React Native Chat App?
React Native is a powerful framework for building fast, responsive, and scalable chat apps on both Android and iOS from a single codebase. This multi-platform support streamlines development, reducing time to market and maintenance costs.
Key benefits when building production-ready chat apps with React:
Performance: With near-native performance, React Native provides a smooth experience, handling large volumes of messages with low latency.
Cross-Platform Consistency: Ensure a consistent user experience across Android and iOS without writing separate code for each platform.
Customizable UI: React Native allows full control over UI components, from chat bubbles to real-time typing indicators, offering flexibility for building tailored chat experiences.
Code Reusability: Reuse much of your code from web apps, speeding up development and reducing maintenance efforts.
Scalability: supports apps that scale effortlessly to millions of users, ensuring your chat app grows with your user base.
Security: Enterprise-level security features like encryption and compliance with HIPAA, GDPR, and SOC2 protect sensitive data.
Large Ecosystem: A vibrant community and extensive resources help developers quickly integrate features like message reactions, file sharing, and push notifications.
React Native provides an efficient path to creating high-quality, cross-platform chat apps while optimizing for performance, scalability, and security.
Prerequisites
Before running this application, be sure you have the following installed:
React Native environment setup, including:
A code editor such as Visual Studio Code
Xcode (for the build step)
Android Studio (for the build step)
If you are using Apple silicon, pay particular attention to any text that mentions "M1". If you already have a development environment setup, ensure it aligns with the versions given in the React Native setup guide, especially JDK and Node.JS.
The PubNub SDKs support applications created with the React Native CLI or the Expo CLI however this tutorial will concentrate on the React Native CLI.
Those developers targeting Expo Go can refer to our separate React Native getting started application, but that is outside of the scope of this tutorial.
Download Free Source Application
This tutorial takes a simple but functional chat app written with React Native and shows how it was developed. You are free to follow the React Native chat tutorial however works for you, either browse through the finished code or add the functionality progressively by checking out the tutorial branch. This code is available for free and released under MIT license.
In a terminal, navigate to an empty folder. Enter the following command to clone the repository:
git clone https://github.com/PubNubDevelopers/GettingStarted-ReactNative-SDK-Tutorial.git
And navigate to the application folder:
cd GettingStarted-ReactNative-SDK-Tutorial
cd GettingStarted
Install the applications dependencies
npm install
To check you have everything set up correctly, you should now be able to build the app for both Android and iOS (remember that iOS development will require a mac).
Android:
npm run android
iOS:
cd ios
pod install
cd ../
npm run ios
(optional) The main git branch contains the completed version of this tutorial. If you would like to add the functionality described in this tutorial progressively into the app then please check out the following tutorial branch:
git checkout tutorial_step_0
Create keys
Demo keys
You're ready to go!
We’ve assigned demo keys which are set up to support the features of this tutorial app. These will be active for 72 hours but you can sign up for a free account at the end of the tutorial to create your own permanent keys.
The demo keys have the following functionality activated ready for your application:
Presence
Message Persistence You will be able to see user’s message history and meta data.
Stream Controller You will be able to receive messages against a group of channels, or post one message to multiple channels.
App Context This allows you to manage the metadata of your users and channels.
My own keys
You'll need to create an account to use your own keysSign in to your PubNub Dashboard.
Go to Keysets using the left hand side navigation.
Click the “Create New Keyset” button on the upper right hand-side of the portal.
A pop-up appears. Give the keyset a name and click the “Create” button.
Click on the newly created keyset.
Enable four features for the keyset to be able to connect to the PubNub Network: Presence, Message Persistence, Stream Controller and App Context.
Enable Presence by clicking on the toggle to turn it on. A pop-up will require that you enter in “ENABLE”. Enter in “ENABLE” in all caps and then press the “Enable” button. You can leave the default settings.
Enable Message Persistence by clicking on the toggle to turn it on. You can leave the default settings.
Enable Stream Controller by clicking on the toggle to turn it on if it is already not enabled. You can leave the default settings.
Enable App Context by clicking on the toggle to turn it on if it is not already enabled. Select the region closest to you to store your context.
Click on the “Save Changes” button in the bottom right corner of the portal. A confirmation message will appear in the upper-left corner of the portal confirming that these changes have been saved.
Scroll back to the top of the portal. Copy the Publish key by clicking on the copy icon and paste it below
Copy the Subscribe Key by clicking on the copy icon and paste it below
Build and run
For clarity, only code from the PubNub SDK is shown in this tutorial. The video will show this code in context with the React Native source
Watch the video or follow the steps below to build and run your application.
//This code box will update soon as you
//progress through the video
//Use the copy icon in the top right to quickly copy
//code as you're following alongStep 1. Add PubNub Keys
You now have your PubNub publish and subscribe keys - copy them from the above section.
Open the PubNubKeys.js file (in the same directory as App.js) and enter the publish and subscribe keys at the relevant location
export const PUBNUB_PUBLISH_KEY = "REPLACE WITH YOUR PUBNUB PUBLISH KEY"
export const PUBNUB_SUBSCRIBE_KEY = "REPLACE WITH YOUR PUBNUB SUBSCRIBE KEY"Step 2. Adding chat to your application with PubNub
The application on the main branch is fully functional and contains all the changes described in the following steps.
If you want to follow along with the tutorial and build the functionality into a templated version of the app, please checkout the following branch:
git checkout tutorial_step_0To run your application at any point use the following:
Android:
npm run android
iOS:
cd ios
pod install
cd ../
npm run iosIf you have installed watchman when setting up your development environment, the application should automatically refresh as you save your code changes. To force a refresh you can bring up the debug menu as detailed in the React Native documentation - you may find this necessary especially if you have a list populated with live data.
Step 2a. Creating the PubNub object
Before interacting with PubNub, you first need to create a PubNub configuration instance. This instance is your entry point into the PubNub SDK and needs to be configured to identify your client to PubNub. The docs lists everything you can do with the instance including access control (access manager) and reconnect settings but this tutorial will only cover basic configuration.
The PubNub instance requires 3 things:
The publish key allows you to send messages using PubNub
The subscribe keys allows you to receive messages with PubNub
The device identifier uniquely identifies your client to PubNub.
The PubNub object is instantiated at the top of the App.js file
const pubnub = new PubNub({
subscribeKey: PubNubKeys.PUBNUB_SUBSCRIBE_KEY,
publishKey: PubNubKeys.PUBNUB_PUBLISH_KEY,
uuid: 'DummyValue',
})The device identifier you pass in should represent a unique instance of the user or device that connects to PubNub. If you maintain your own user registration workflow then you could use whichever unique identifier you assigned the user during registration. If your users do not already have an assigned ID, as in the case of this app, you should assign a device-specific identifier. More information on the device identifier can be found in this PubNub support article.
Obtaining a device-specific identifier requires platform-specific code but there is a useful React Native plugin that does this for us, device-info. Expo users can use the Expo device API, which serves the same purpose.
deviceId = await DeviceInfo.getUniqueId()
pubnub.setUUID(deviceId)Step 2b. Subscribing to a channel
The concepts of publish and subscribe are fundamental to PubNub where messages are sent from a publishing source and received by subscribers over a channel. You do not need to create the channel separately, it will be created automatically for you by PubNub whenever the first user publishes or subscribes to it.
Despite the apparent simplicity, the Pub/Sub model is able to accommodate the most complex of communication use cases.
To keep this application simple we will only have a single channel to represent the application’s single "chat room". The application will subscribe to receive messages from the channel that have been published by other users.
On mobile applications, you cannot rely on your application being active in the background so most chat developers will take a two stage approach:
Subscribe to receive messages when the app comes to the foreground
Unsubscribe when the app goes into the background
Receive a mobile push notification whilst in the background to notify the user that a message is available. This is outside of the scope of this tutorial but please see our Push Notifications tutorial for more information.
Since we want to receive presence events when users join or leave the channel, specify ‘withPresence’ to be true.
Subscribe to the channel when the app comes to the foreground, this is detected by the handleChange function, in App.js:
pubnub.subscribe({channels: [groupChatChannel], withPresence: true})Unsubscribe from the channel when the app goes into the background, also detected by the handleChange function, in App.js:
pubnub.unsubscribe({channels: [groupChatChannel]})Step 2c. Publishing messages to a channel
Messages published to a channel will be received by all subscribers on that channel. Note that we are using the same channel name that we previously subscribed to.
To keep this application simple, the message payload is a String. Your application will likely use a JSON object rather than a string, which allows you to add custom ‘meta’ information to the message.
Add this code to the handleSend() function, the send button click handler in App.js (React Native component code has been omitted from this tutorial for readability, this also includes state management, i.e. useState()):
pubnub.publish({channel: groupChatChannel, message: input})Step 2d. Listening for PubNub events
PubNub event listeners are used to receive:
Messages: A message has been received.
Presence information: A user has joined or left a channel.
Signals: A signal has been received.
App Context: PubNub's serverless storage has been updated
Message Reactions: Used to modify messages after they are published, for example adding an emoji reaction.
App Context requires the 'App Context' feature to be enabled on the keyset, which was done during the ‘Create Keys’ section of this tutorial.
This tutorial only uses a subset of the possible listeners which will be populated in upcoming steps. Production apps will also often use status events to detect any communication or network errors.
The JavaScript SDK allows you to define a single listener object to receive all event types. The event listener is defined when the app first starts and the sample does this within a useEffect() as part of initialization, in App.js (React Native component code has been omitted from this tutorial for readability):
const listener = {
message: receivedMsg => {
// todo (Tutorial step 2e)
},
presence: presenceMsg => {
// todo (Tutorial step 2f 1/2))
},
objects: objMsg => {
// todo (Tutorial step 2i)
},
}
pubnub.addListener(listener)Step 2e. Listening for new messages
Once an application subscribes to messages on a channel, the messages will be received by the message listener, created at step 2d.
Update the ‘message:’ condition as follows to update the List of chat messages which are defined in a Hook (React Native component code has been omitted from this tutorial for readability):
setMessages(msgs => [
...msgs,
{
id: receivedMsg.timetoken,
author: receivedMsg.publisher,
content: receivedMsg.message,
timetoken: receivedMsg.timetoken,
},
])Step 2f. Listening for presence events
By subscribing to a channel’s presence events, as was done in step 2b, we will also receive events whenever a user joins or leaves the channel.
Update the ‘presence:’ condition with the following cases:
if (presenceMsg.action == 'join') {
addMember(presenceMsg.uuid)
} else if (presenceMsg.action == 'leave') {
removeMember(presenceMsg.uuid)
} else if (presenceMsg.action == 'interval') {
if (presenceMsg['join'] != undefined) {
for (var i = 0; i < presenceMsg['join'].length; i++) {
addMember(presenceMsg['join'][i])
}
}
if (presenceMsg['leave'] != undefined) {
for (var i = 0; i < presenceMsg['leave'].length; i++) {
removeMember(presenceMsg['leave'][i])
}
}
}When the application first starts, it needs to populate the list of users currently in the channel. Since presence events only apply to users newly joining or leaving, the application calls the ‘hereNow’ function on launch to retrieve a list of device IDs already in the group chat. This should be added to the same useEffect() code described earlier which is invoked during initialization, in App.js (React Native component code has been omitted from this tutorial for readability):
pubnub
.hereNow({
channels: [groupChatChannel],
includeUUIDs: true,
})
.then(devicesHereNow => {
try {
var occupants =
devicesHereNow['channels'][groupChatChannel]['occupants']
occupants.forEach(function (member, index) {
addMember(occupants[index].uuid)
})
} catch (error) {
// Error executing hereNow
}
})Step 2g. Retrieving past messages
When a user first joins the chat, it is often useful to provide some recently sent messages, to give some context of any conversation in progress.
Alternatively, if a user leaves and then rejoins the chat they will need to get up to speed on any messages they missed whilst they were away.
Both of these use cases are handled by the PubNub Message Persistence API.
During the initialisation of the app, just after where we added the listener in step 2d, add the following code:
pubnub
.fetchMessages({
channels: [groupChatChannel],
includeUUID: true,
count: 8,
})
.then(historicalMessages => {
var historicalMessagesArray =
historicalMessages['channels'][groupChatChannel]
for (var i = 0; i < historicalMessagesArray.length; i++) {
var message = historicalMessagesArray[i]
lookupMemberName(message.uuid)
setMessages(msgs => [
...msgs,
{
id: message.timetoken,
author: message.uuid,
content: message.message,
timetoken: message.timetoken,
},
])
}
})Step 2h. Assign a friendly name to the device and persist it with PubNub Object storage
App Context is a very powerful serverless storage mechanism provided by PubNub and designed to meet many use cases of a standard chat app.
For example, you can choose to use App Context to store:
User meta data such as name, avatar, email
Channel metadata such as name and description as well as who the members of that channel are
This application does not take full advantage of App Context but does store a single piece of information, the ‘friendly name’ that the user can assign themselves. Assigning a friendly name avoids having to display the long device ID in the member list.
Setting the ‘friendly name’ is handled by a textfield towards the top of the application, modify the ‘save’ button click handler, ‘handleSaveFriendlyName’, in App.js to save the name to the PubNub User meta data.
try {
const result = await pubnub.objects.setUUIDMetadata({
data: {
name: myFriendlyName,
},
})
} catch (status) {
console.log('Save friendly name status: ' + status)
}Step 2i. Lookup someone else's friendly name using PubNub Object storage
The PubNub App Context store is considered the master copy of ‘friendly names’ set by anyone involved in the chat, as detailed in step 2h.
The presence listener, described in step 2f, only tells you the device IDs of users joining or leaving the chat. To update the list of member friendly names in the chat, add the following code to the lookupMemberName() function, in App.js
try {
const result = await pubnub.objects.getUUIDMetadata({
uuid: deviceIdentifier,
})
var newFriendlyNames = friendlyNames
newFriendlyNames[deviceIdentifier] = result.data.name
setFriendlyNames({...newFriendlyNames})
if (deviceIdentifier == deviceId) {
setMyFriendlyName(result.data.name)
}
// Force an update of the messages view with the new name
setMessages(msgs => [...msgs])
} catch (error) {
// This happens if the UUID is not known on the server which is
// a common occurrence so just swallow this
}What about if another user changes their friendly name? To be notified when the friendly name changes, populate the ‘objects’ condition in the listener callback you defined back in step 2d. This listener will fire whenever any member user meta data is updated.
if (objMsg.message.type == 'uuid') {
replaceMemberName(objMsg.message.data.id, objMsg.message.data.name)
}One additional point about the ‘objects’ (App Context) listener: You must have “User Metadata Events” applied to your keyset, as below.
UI Notes and other caveats
For efficiency, PubNub handles presence slightly differently depending on how many occupants you have in the channel. If using this app with a number of users above the ‘Announce Max’ setting, which defaults to 20, be sure to enable the ‘Presence Deltas’ option in your admin dashboard. This causes PubNub to report the device IDs who have joined or left as part of the interval event, which this app uses to maintain who is in the channel.
As stated earlier, mobile applications rely on push notification to receive messages whilst in the background. That is outside of the scope of this tutorial, but please see our Push Notifications tutorial for more information.
This tutorial did not cover read receipts. For information on adding read receipts to your application, please see our documentation for message reactions.
As I created the sample app, I focused on showing PubNub functionality rather than creating an impressive UI... as you can tell, user interface design is not my strongest skill :)
Congratulations - what's next?
Chat SDK Documentation
Chat OverviewJavaScript SDK DocsReact SDK DocsChat Developer PathLive Tour
Start the live coding tourExplore other Sample apps
Simple React Native reference appDeveloping to a tight deadline? Explore Chat Components
Chat Components IntroductionReady to get beyond Proof of Concept?
Schedule a 15 minute chat with one of our experts to get your project moving
Talk to an ExpertTake it to production on your own keys
Create a free PubNub account to get permanent keys for this app.