Simple Multi User Chat App Example Using Node.js, WebSocket and Flutter
In this app example, we have made a communication server with node.js that helps to transfer messages from one user to another user. It is a multiuser chat app, which means one user can send a message to another specific user. See the example below for more details.
const WebSocket = require('ws')
const express = require('express')
const moment = require('moment')
const app = express()
const port = 7878; //port for https
app.get('/', (req, res) => {
res.send("Hello World");
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
});
var webSockets = {}
const wss = new WebSocket.Server({ port: 6060 }) //run websocket server with port 6060
wss.on('connection', function (ws, req) {
var userID = req.url.substr(1) //get userid from URL ip:6060/userid
webSockets[userID] = ws //add new user to the connection list
console.log('User ' + userID + ' Connected ')
ws.on('message', message => { //if there is any message
console.log(message);
var datastring = message.toString();
if(datastring.charAt(0) == "{"){
datastring = datastring.replace(/\'/g, '"');
var data = JSON.parse(datastring)
if(data.auth == "chatapphdfgjd34534hjdfk"){
if(data.cmd == 'send'){
var boardws = webSockets[data.userid] //check if there is reciever connection
if (boardws){
var cdata = "{'cmd':'" + data.cmd + "','userid':'"+data.userid+"', 'msgtext':'"+data.msgtext+"'}";
boardws.send(cdata); //send message to reciever
ws.send(data.cmd + ":success");
}else{
console.log("No reciever user found.");
ws.send(data.cmd + ":error");
}
}else{
console.log("No send command");
ws.send(data.cmd + ":error");
}
}else{
console.log("App Authincation error");
ws.send(data.cmd + ":error");
}
}else{
console.log("Non JSON type data");
ws.send(data.cmd + ":error");
}
})
ws.on('close', function () {
var userID = req.url.substr(1)
delete webSockets[userID] //on connection close, remove reciver from connection list
console.log('User Disconnected: ' + userID)
})
ws.send('connected'); //innitial connection return message
})
Make sure you have installed modules such as express
, ws
and moment
. Use the following command lines to install these modules.
npm install express --save
npm install ws --save
npm install moment --save
Run the node.js script using the following command:
node app.js
Now on the flutter part, add web_socket_channel flutter package to your dependency by adding the following line to your pubspec.yaml file.
dependencies:
flutter:
sdk: flutter
web_socket_channel: ^2.0.0
Add Internet Permission by adding this line in android/app/src/main/AndroidManifest.xml before <application>
<uses-permission android:name="android.permission.INTERNET"/>
Here we are using ws
, non-secure WebSocket protocol. Therefore, add the following lines to AndroidManifest.xml file as well.
<application
android:usesCleartextTraffic="true"
We have two files in the Flutter project:
- main.dart
- chat.dart
import 'package:chatapp/chat.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Chat App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: ChatPage(),
);
}
}
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:web_socket_channel/io.dart';
class ChatPage extends StatefulWidget{
@override
State<StatefulWidget> createState() {
return ChatPageState();
}
}
class ChatPageState extends State<ChatPage>{
IOWebSocketChannel channel; //channel varaible for websocket
bool connected; // boolean value to track connection status
String myid = "222"; //my id
String recieverid = "111"; //reciever id
// swap myid and recieverid value on another mobile to test send and recieve
String auth = "chatapphdfgjd34534hjdfk"; //auth key
List<MessageData> msglist = [];
TextEditingController msgtext = TextEditingController();
@override
void initState() {
connected = false;
msgtext.text = "";
channelconnect();
super.initState();
}
channelconnect(){ //function to connect
try{
channel = IOWebSocketChannel.connect("ws://192.168.0.109:6060/$myid"); //channel IP : Port
channel.stream.listen((message) {
print(message);
setState(() {
if(message == "connected"){
connected = true;
setState(() { });
print("Connection establised.");
}else if(message == "send:success"){
print("Message send success");
setState(() {
msgtext.text = "";
});
}else if(message == "send:error"){
print("Message send error");
}else if (message.substring(0, 6) == "{'cmd'") {
print("Message data");
message = message.replaceAll(RegExp("'"), '"');
var jsondata = json.decode(message);
msglist.add(MessageData( //on message recieve, add data to model
msgtext: jsondata["msgtext"],
userid: jsondata["userid"],
isme: false,
)
);
setState(() { //update UI after adding data to message model
});
}
});
},
onDone: () {
//if WebSocket is disconnected
print("Web socket is closed");
setState(() {
connected = false;
});
},
onError: (error) {
print(error.toString());
},);
}catch (_){
print("error on connecting to websocket.");
}
}
Future<void> sendmsg(String sendmsg, String id) async {
if(connected == true){
String msg = "{'auth':'$auth','cmd':'send','userid':'$id', 'msgtext':'$sendmsg'}";
setState(() {
msgtext.text = "";
msglist.add(MessageData(msgtext: sendmsg, userid: myid, isme: true));
});
channel.sink.add(msg); //send message to reciever channel
}else{
channelconnect();
print("Websocket is not connected.");
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("My ID: $myid - Chat App Example"),
leading: Icon(Icons.circle, color: connected?Colors.greenAccent:Colors.redAccent),
//if app is connected to node.js then it will be gree, else red.
titleSpacing: 0,
),
body: Container(
child: Stack(children: [
Positioned(
top:0,bottom:70,left:0, right:0,
child:Container(
padding: EdgeInsets.all(15),
child: SingleChildScrollView(
child:Column(children: [
Container(
child:Text("Your Messages", style: TextStyle(fontSize: 20)),
),
Container(
child: Column(
children: msglist.map((onemsg){
return Container(
margin: EdgeInsets.only( //if is my message, then it has margin 40 at left
left: onemsg.isme?40:0,
right: onemsg.isme?0:40, //else margin at right
),
child: Card(
color: onemsg.isme?Colors.blue[100]:Colors.red[100],
//if its my message then, blue background else red background
child: Container(
width: double.infinity,
padding: EdgeInsets.all(15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
child:Text(onemsg.isme?"ID: ME":"ID: " + onemsg.userid)
),
Container(
margin: EdgeInsets.only(top:10,bottom:10),
child: Text("Message: " + onemsg.msgtext, style: TextStyle(fontSize: 17)),
),
],),
)
)
);
}).toList(),
)
)
],)
)
)
),
Positioned( //position text field at bottom of screen
bottom: 0, left:0, right:0,
child: Container(
color: Colors.black12,
height: 70,
child: Row(children: [
Expanded(
child: Container(
margin: EdgeInsets.all(10),
child: TextField(
controller: msgtext,
decoration: InputDecoration(
hintText: "Enter your Message"
),
),
)
),
Container(
margin: EdgeInsets.all(10),
child: ElevatedButton(
child:Icon(Icons.send),
onPressed: (){
if(msgtext.text != ""){
sendmsg(msgtext.text, recieverid); //send message with webspcket
}else{
print("Enter message");
}
},
)
)
],)
),
)
],)
)
);
}
}
class MessageData{ //message data model
String msgtext, userid;
bool isme;
MessageData({this.msgtext, this.userid, this.isme});
}
Read the comments inside the code to understand better.
User with ID: 111 | User with ID: 222 |
In this way, you can make an instant chat app with the multiuser, database-less features. Study the code, and understand the basic method to build a chat app using node.js and Flutter.
Please Wait...
No any Comments on this Article