Tạo app chat đơn giản với socket và flutter cùng với nodejs

Avatar admin | March 31, 2023

Tạo app chat với ứng dụng chat của chúng tôi! Đây là một ứng dụng nhắn tin đa nền tảng,
cho phép người dùng gửi và nhận tin nhắn một cách nhanh chóng và dễ dàng.

Giới thiệu

Với thiết kế giao diện thân thiện và tính năng đầy đủ, ứng dụng chat của chúng tôi sẽ giúp
bạn kết nối với bạn bè và gia đình của mình một cách thú vị và tiện lợi.

Bạn có thể gửi tin nhắn văn bản, hình ảnh, đồng thời chat trong nhóm và nhiều tính năng khác
nữa.

Hãy tải ứng dụng chat của chúng tôi và bắt đầu trò chuyện với bạn bè của mình ngay bây
giờ!

Về phần mobile với code flutter

Đây là một ví dụ cơ bản về ứng dụng Flutter với kết nối socket để gửi và nhận tin
nhắn qua một máy chủ socket.

Trong ví dụ này, tôi sử dụng package socket_io_client để kết nối socket.

Đầu tiên, bạn cần thêm package socket_io_client vào file pubspec.yaml và chạy flutter packages get để cài đặt.

dependencies:
  flutter:
    sdk: flutter
  socket_io_client: ^2.0.0-beta.4

Sau đó, bạn có thể tạo một Flutter StatefulWidget và sử dụng Socket để kết nối và nhận tin nhắn
từ máy chủ.

import 'package:flutter/material.dart';
import 'package:socket_io_client/socket_io_client.dart' as IO;

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Socket Chat',
      home: ChatScreen(),
    );
  }
}

class ChatScreen extends StatefulWidget {
  @override
  _ChatScreenState createState() => _ChatScreenState();
}

class _ChatScreenState extends State<ChatScreen> {
  IO.Socket socket;
  TextEditingController _messageController = TextEditingController();
  List<String> _messages = [];

  @override
  void initState() {
    super.initState();
    connectToSocket();
  }

  void connectToSocket() {
    socket = IO.io('https://mtips5s.com:3000', <String, dynamic>{
      'transports': ['websocket'],
    });

    socket.on('connect', (_) {
      print('connected');
    });

    socket.on('message', (data) {
      setState(() {
        _messages.add(data);
      });
    });

    socket.on('disconnect', (_) {
      print('disconnected');
    });
  }

  void sendMessage(String message) {
    if (message.isNotEmpty) {
      socket.emit('message', message);
      _messageController.clear();
    }
  }

  @override
  void dispose() {
    socket.disconnect();
    _messageController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Socket Chat'),
      ),
      body: Column(
        children: [
          Expanded(
            child: ListView.builder(
              itemCount: _messages.length,
              itemBuilder: (context, index) {
                return ListTile(
                  title: Text(_messages[index]),
                );
              },
            ),
          ),
          TextField(
            controller: _messageController,
            decoration: InputDecoration(
              hintText: 'Type a message...',
            ),
            onSubmitted: sendMessage,
          ),
        ],
      ),
    );
  }
}

Về phần server ta sử dụng nodejs

Đây là một mẫu code Node.js đơn giản để bắt đầu xây dựng một ứng dụng web:

const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(port, () => {
  console.log(`Example app listening at https://mtips5s.com:${port}`);
});

Trong đoạn mã này, chúng ta sử dụng framework Express để tạo một ứng dụng web đơn giản. Chúng ta
khai báo biến app và gán nó bằng express(). Sau đó, chúng ta khai báo biến port để lưu cổng
mà ứng dụng của chúng ta sẽ lắng nghe.

Chúng ta đăng ký một xử lý router cho đường dẫn chính của ứng dụng bằng cách sử dụng phương
thức app.get(). Nếu có yêu cầu HTTP GET gửi đến đường dẫn ‘/’, chúng ta gửi một chuỗi ‘Hello World!’
trả về cho client.

Cuối cùng, chúng ta gọi phương thức app.listen() để bắt đầu lắng nghe các kết nối đến ứng dụng của
chúng ta trên cổng được chỉ định. Khi ứng dụng của chúng ta bắt đầu lắng nghe các kết nối
đến, chúng ta in ra một thông báo trên console để cho biết ứng dụng của chúng ta đã được
khởi chạy thành công và đang lắng nghe các kết nối đến.

Tạo app chat: Cài đặt thêm socketIO hỗ trợ lắng nghe chat

Đây là một ví dụ về việc lắng nghe kết nối socket từ ứng dụng Flutter ở trên bằng một
máy chủ socket đơn giản bằng Node.js. Trong ví dụ này, chúng ta sử dụng package socket.io để tạo một
máy chủ socket.

Đầu tiên, bạn cần tạo một thư mục mới và chạy lệnh sau để cài đặt package socket.io:

npm install socket.io

Sau đó, tạo một file server.js và thêm mã sau vào nó:

const io = require('socket.io')(3000);

io.on('connection', (socket) => {
  console.log('connected');

  socket.on('message', (message) => {
    console.log(`received message: ${message}`);
    io.emit('message', message);
  });

  socket.on('disconnect', () => {
    console.log('disconnected');
  });
});

Trong đoạn mã này, chúng ta đang tạo một kết nối socket trên cổng 3000 và lắng nghe sự kiện
‘connection’ từ các client.

Khi có một kết nối mới được tạo, chúng ta lắng nghe sự kiện ‘message’ để nhận tin nhắn từ
client và sử dụng phương thức emit của Socket để gửi tin nhắn đó tới tất cả các client đang
kết nối.

Bạn có thể chạy file server.js bằng cách sử dụng lệnh sau:

node server.js

Sau đó, bạn có thể chạy ứng dụng Flutter của mình và nhập mtips5s.com:3000 vào địa chỉ máy chủ để
kết nối với máy chủ socket của bạn.

Khi bạn nhập một tin nhắn trong ứng dụng của mình, tin nhắn đó sẽ được gửi đến máy chủ
socket và được phát lại tới tất cả các client đang kết nối đến máy chủ socket của bạn.

Full Code nodejs

SocketIO trên Nodejs

Tạo app chat: Tạo phần reply trên flutter

Đây là một đoạn mã Flutter đơn giản để tạo thêm trang trả lời bằng Socket với vai trò người
dùng thứ 2:

import 'dart:convert';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:socket_io_client/socket_io_client.dart' as IO;

class ReplyPage extends StatefulWidget {
  final IO.Socket socket;
  final String username;

  ReplyPage({Key key, this.socket, this.username}) : super(key: key);

  @override
  _ReplyPageState createState() => _ReplyPageState();
}

class _ReplyPageState extends State<ReplyPage> {
  TextEditingController _textEditingController = TextEditingController();
  List<String> _messages = [];

  @override
  void initState() {
    super.initState();
    widget.socket.on('receive_message', (data) {
      setState(() {
        _messages.add(data['username'] + ': ' + data['message']);
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Reply Page'),
      ),
      body: Column(
        children: [
          Expanded(
            child: ListView.builder(
              itemCount: _messages.length,
              itemBuilder: (context, index) {
                return Padding(
                  padding: EdgeInsets.all(10.0),
                  child: Text(_messages[index]),
                );
              },
            ),
          ),
          Container(
            margin: EdgeInsets.all(10.0),
            child: Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: _textEditingController,
                    decoration: InputDecoration(
                      hintText: 'Enter your message',
                      border: OutlineInputBorder(),
                    ),
                  ),
                ),
                IconButton(
                  icon: Icon(Icons.send),
                  onPressed: () {
                    if (_textEditingController.text.isNotEmpty) {
                      widget.socket.emit('send_message', {
                        'username': widget.username,
                        'message': _textEditingController.text,
                      });
                      setState(() {
                        _messages.add(widget.username +
                            ': ' +
                            _textEditingController.text);
                      });
                      _textEditingController.clear();
                    }
                  },
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}


Trong đoạn mã này, chúng ta sử dụng package socket_io_client để kết nối và gửi/nhận thông tin qua socket. Chúng
ta khai báo một widget ReplyPage để hiển thị trang trả lời và gửi thông tin qua socket.

Chúng ta sử dụng initState() để lắng nghe các sự kiện socket receive_message từ server. Khi có một thông điệp
được gửi từ người dùng khác, chúng ta sẽ thêm thông điệp đó vào danh sách _messages và cập nhật
giao diện bằng cách gọi setState().

Ở phần giao diện, chúng ta sử dụng một ListView.builder() để hiển thị danh sách các thông điệp được nhận.
Ở phần cuối cùng của widget, chúng ta hiển thị một TextField để người dùng nhập nội dung tin nhắn
và một IconButton để gửi tin nhắn. Khi người dùng nhấn vào nút gửi tin nhắn

Tạo app chat: Tạo một button navigate sang screen trả lời

Để tạo một button để chuyển sang một trang mới trong Flutter, bạn có thể sử dụng widget ElevatedButton hoặc
FlatButton và đặt nó vào trong một hàm onPressed để điều hướng đến trang mới.

Ví dụ, để tạo một button Navigate to Screen 2 và điều hướng đến trang mới khi nó được nhấn,
bạn có thể sử dụng đoạn mã sau:





Center(
        child: ElevatedButton(
          child: Text('Navigate to Screen 2'),
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => Screen2()),
            );
          },
        ),
      )

Trong ví dụ này, chúng ta đặt một ElevatedButton vào trong phần thân của trang Screen1. Khi người dùng nhấn
vào nút, chúng ta sử dụng hàm Navigator.push() để điều hướng đến trang mới Screen2. Chúng ta cũng cần import
file screen2.dart để sử dụng trang này trong hàm Navigator.push(). Lưu ý rằng context được truyền vào trong hàm Navigator.push()
là context của trang hiện tại, và builder là một hàm trả về trang mới mà bạn muốn điều hướng
đến.

Kết luận

Phần tiếp theo tôi sẽ lên tối ưu hơn, thêm nhiều chức năng hơn cho đoạn code trên 🙂 Đợi
nhé bạn

#mtips5s contact

Fanpage: https://www.facebook.com/mtips5s

Group trao đổi, chia sẻ: https://www.facebook.com/groups/mtips5s

Website: https://mtips5s.com

Youtube: https://mtips5s.com

Chúc các bạn thành công!

Các lần chỉnh sửa

  • v1.0 03/04/2023: Viết bài

def create_profile():
    with open('_4_write_profile.html', 'r') as f:
        text = f.read()
    print("4. Tạo profile")
    return text

Written by admin


Comments

This post currently has no responses.

Leave a Reply