Two-Way, Real-Time Communication with WebSockets in Flutter Apps (+ Node.js Backend)
Teqani Blogs
Writer at Teqani
Real-time data exchange is at the heart of many modern apps—chats, multiplayer games, trading dashboards, and collaborative tools. In this tutorial, you’ll learn how to build a two-way real-time communication system using Flutter on the frontend and a Node.js WebSocket server on the backend. This is crucial for creating engaging and interactive user experiences.
Setting up the Node.js WebSocket Server
Let's start by setting up a basic WebSocket server using the popular ws
library. First, initialize your project and install the necessary dependencies:
- Setup
Install dependencies:
npm init -y
npm install ws
Next, create your server.js
file:
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws) {
console.log('Client connected');
ws.on('message', function incoming(message) {
console.log('received: %s', message);
// Echo the message back to all clients
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send(`Echo: ${message}`);
}
});
});
ws.send('Welcome to the WebSocket server!');
});
console.log("WebSocket server running on ws://localhost:8080");
Run the server:
node server.js
Building the Flutter Client
Now, let's build the Flutter client. Add web_socket_channel
as a dependency to your pubspec.yaml
:
dependencies:
flutter:
sdk: flutter
web_socket_channel: ^2.3.0
Here’s the main.dart
code for the Flutter client:
import 'package:flutter/material.dart';
import 'package:web_socket_channel/web_socket_channel.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final WebSocketChannel channel =
WebSocketChannel.connect(Uri.parse('ws://localhost:8080'));
@override
Widget build(BuildContext context) {
return MaterialApp(
home: ChatScreen(channel: channel),
);
}
}
class ChatScreen extends StatefulWidget {
final WebSocketChannel channel;
ChatScreen({required this.channel});
@override
_ChatScreenState createState() => _ChatScreenState();
}
class _ChatScreenState extends State
final TextEditingController _controller = TextEditingController();
final List
@override
void initState() {
super.initState();
widget.channel.stream.listen((message) {
setState(() {
_messages.add(message);
});
});
}
void _sendMessage() {
if (_controller.text.isNotEmpty) {
widget.channel.sink.add(_controller.text);
_controller.clear();
}
}
@override
void dispose() {
widget.channel.sink.close();
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Flutter WebSocket Chat")),
body: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: _messages.length,
itemBuilder: (_, index) => ListTile(
title: Text(_messages[index]),
),
),
),
Padding(
padding: const EdgeInsets.all(12),
child: Row(
children: [
Expanded(child: TextField(controller: _controller)),
IconButton(
icon: Icon(Icons.send),
onPressed: _sendMessage,
)
],
),
)
],
),
);
}
}
In this tutorial, we built a working prototype of a bi-directional real-time chat system using a Node.js WebSocket server and a Flutter client, making use of the web_socket_channel
package.
All blogs are certified by our company and reviewed by our specialists
Issue Number: #e4a97227-2563-483b-ae43-9d1c99876846