Building a Realtime Chat App with Flutter, Node.js & Socket.IO

Building a Realtime Chat App with Flutter, Node.js & Socket.IO

Instant messaging has revolutionized how we communicate with each other, you could send a message to anyone anywhere in the world and they would instantly receive it.

Instant messaging applications like WhatsApp, Messenger and Instagram make use of real-time mode of communications which simply means that users can exchange information instantly or with negligible latency.

In this article, we will talk about how we can use Socket.IO to build a real-time chat application using Node.js as the backend and Flutter as the frontend. Let’s get started!

What is Socket.IO?

Here’s a formal definition from Socket.IO: Socket.IO is a library that enables real-time, bidirectional and event-based communication between the browser and the server. Now let’s take a look at how Socket.IO works…

Socket.IO establishes a connection between the client and the server using the WebSocket protocol, but if that fails, it falls back to using HTTP long-polling to make a successful connection.

Why Use Socket.IO Over HTTP Rest API?

HTTP is a request-response protocol, which means a client requests a data from a server, in return the server sends a response to that request. The downside to this is, for each message being sent, there's a new request-response being made, and since HTTP request-response protocol isn't a “keep-alive” (persistent) type of communication you'll have to make multiple HTTP connections when sending multiple messages resulting to high network latency thereby defeating the purpose of having a real-time chat application.

Socket.IO, on the other hand, operates on a persistent bi-directional data transfer system, which means that the connection is kept alive and messages are sent/received instantly or with negligible latency.

Let’s build out a project so you can see how we use Socket.IO to build a real-time chat application.

Setting up the Server (Node.js)

Step 1:

  • Create a new folder with the desired name of your project, I'll name mine socket_io_chat_server.
  • Create a package.json file in the root of the folder
  • Now run npm init in your terminal, before you do this make sure you switch your current directory to that folder
  • Next, install the following packages through npm in your terminal.
\socket_io_chat_server> npm install http
\socket_io_chat_server> npm install socket.io
\socket_io_chat_server> npm install nodemon 
\socket_io_chat_server> npm install express

Step 2:

Once all of our packages have been installed, we will create an app.js file that will contain all of our Socket.IO configurations.

After you've created the app.js file, copy and paste the code below into it.

const httpServer = require('http').createServer()
const socketIO = require('socket.io')(httpServer)

socketIO.on('connection', function (client) {
  console.log('Connected...', client.id);

//listens for new messages coming in
  client.on('message', function name(data) {
    console.log(data);
    socketIO.emit('message', data);
  })

//listens when a user is disconnected from the server
  client.on('disconnect', function () {
    console.log('Disconnected...', client.id);
  })

//listens when there's an error detected and logs the error on the console
  client.on('error', function (err) {
    console.log('Error detected', client.id);
    console.log(err);
  })
})

var port = process.env.PORT || 3000;
httpServer.listen(port, function (err) {
  if (err) console.log(err);
  console.log('Listening on port', port);
});

From the code above, we simply created a HTTP server using the http module, we also created an instance of the Socket.IO module and passed in the httpServer as an argument. Then we listen on the connection event for incoming sockets and once a socket is connected to our app we log it on the console, same thing goes for the message event, it listens for new messages coming in and logs it in the console.

Step 3:

In the previous step, notice that we called the listen method on our httpServer to listen for connections on our port. Now let’s start our server by running nodemon app.js in our terminal.

You should see something like this:

The server has been started and it’s listening on port 3000

The image above indicates that the server has been started and it’s listening on port 3000. Now that our server is up and running, let’s move on to setting up the client using Flutter as our frontend.

Setting up the Client (Flutter)

Step 1:

Create a new Flutter project by running the command below in your terminal:

flutter create socket_io_client_chat

Step 2:

Once this operation has finished, we need to add the socket_io_client package as a dependency to our project. You can do that by running the following command in your terminal:

flutter pub add socket_io_client

This will add the Socket.IO client to your dependency in your pubspec.yaml file.

I'll be leaving out the bulky UI codes of our Chat Screen for the sake of simplicity, and instead focus solely on how to initialize the Socket.IO client, listening to socket events and send messages using the client.

You can check out the full repo of this project on GitHub here 😉 . Don’t forget to star ⭐ the repo if you enjoy the article. Moving on…

Step 3: Initializing the Socket.IO Client

The code below is a simple implementation of initializing the Socket.IO client and listening to events received from the Server.

We use the on method on the Socket.IO object to listen to events from our Server.

...
  Socket socket; //initalize the Socket.IO Client Object 

  @override
  void initState() {
    super.initState();
    initializeSocket(); //--> call the initializeSocket method in the initState of our app.
  }

 @override
  void dispose() {
    socket.disconnect(); // --> disconnects the Socket.IO client once the screen is disposed 
    super.dispose();
  }

void initializeSocket() {
      socket =
          io("http://127.0.0.1:3000/", <String, dynamic>{
        "transports": ["websocket"],
        "autoConnect": false,
      });
      socket.connect();  //connect the Socket.IO Client to the Server

      //SOCKET EVENTS
      // --> listening for connection 
      socket.on('connect', (data) {  
        print(socket.connected);
      });

      //listen for incoming messages from the Server. 
      socket.on('message', (data) {
       print(data); //
      });

      //listens when the client is disconnected from the Server 
      socket.on('disconnect', (data) {
        print('disconnect');
      });
  }

Step 4:

In the previous step we initialized our Socket.IO client, now let’s look at how to send messages with the client. To send messages to our server, we need to make use of the emit method on the Socket.IO object.

The emit method is used to send events between the client and the server.

  sendMessage(String message) {
      socket.emit("message",
        {
          "id": socket.id,
          "message": message, //--> message to be sent
          "username": username,
          "sentAt": DateTime.now().toLocal().toString().substring(0, 16),
        },
      );
  }

From the code above, the emit method on the Socket.IO object takes in two arguments, the event name and the object to be sent over to the Server. In our case, the event name here is message and the object we are to send are the properties of our message.

⚠️ Note

Before launching your Flutter application, run adb reverse tcp:3000 tcp:3000 in your terminal to resolve the issue of connecting to localhost on Android devices.

Conclusion

To wrap this up, Socket.IO makes it really simple for us to build a real-time chat application, and we have learnt what Socket.IO is, how it works, and why we choose Socket.IO over the traditional HTTP REST API. We also built a basic real-time chat application using Flutter as frontend and Node.js as the backend.

I hope you find this article useful and if you do please share. ☺️