실시간 채팅 앱 - Flutter, Node.js 및 Socket.io

이 블로그에서는 Node.js를 백엔드로 사용하고 Flutter를 프런트엔드로 사용하여 실시간 채팅 앱을 만드는 방법을 살펴보겠습니다. 장치 간 통신을 위해 소켓을 사용합니다.

전제 조건
다음이 PC에 설치되어 실행 중이어야 합니다.
  • Node.js: https://nodejs.org/en/download/
  • 플러터 : https://flutter.dev/docs/get-started/install
  • Heroku CLI: https://devcenter.heroku.com/articles/heroku-cli
  • 자식 : https://git-scm.com/downloads

  • Nodejs(서버 측)



    real_chat_node라는 폴더를 만들고 터미널에서 엽니다. 그런 다음 다음 명령을 실행합니다.
    npm init
    Enter를 눌러 기본값을 승인하십시오. 다음으로 노드를 설치할 때 기본적으로 제공되는 npm을 통해 필요한 패키지를 설치합니다.
    npm install express nodemon http socket.io
    즐겨찾는 IDE로 폴더를 엽니다. 그런 다음 package.json으로 이동하고 스크립트에서 개발 키를 추가합니다.



    다음으로 루트 디렉터리에 index.js 파일을 만듭니다. 그 안에 다음 코드를 작성합니다.

    const app = require('express')()
    const http = require('http').createServer(app)
    app.get('/', (req, res) => {
       res.send("Node Server is running. Yay!!")
    })
    http.listen(8080)
    

    터미널에서 다음 명령을 입력합니다.npm run dev
    실행 상태로 두고 http://localhost:8080으로 이동하면 메시지가 표시됩니다.

    이제 nodejs 앱에 소켓을 추가하겠습니다.

    const app = require('express')()
    const http = require('http').createServer(app)
    
    
    app.get('/', (req, res) => {
        res.send("Node Server is running. Yay!!")
    })
    
    //Socket Logic
    const socketio = require('socket.io')(http)
    
    socketio.on("connection", (userSocket) => {
        userSocket.on("send_message", (data) => {
            userSocket.broadcast.emit("receive_message", data)
        })
    })
    
    http.listen(process.env.PORT)
    

    연결 이벤트는 소켓이 앱에 연결될 때마다 트리거됩니다. 그런 다음 수신된 모든 데이터를 receive_message 이벤트로 전달하는 send_message 이벤트에 수신기를 추가합니다.

    짜잔!! 백엔드가 준비되었습니다. heroku에 배포한 다음 Flutter 앱을 시작할 수 있습니다.

    빠른 참고: 다음은 이벤트를 보내고 받는 방법입니다.

    Heroku(배포)



    Heroku는 URL을 통해 어디서나 액세스할 수 있도록 앱을 배포하는 클라우드 플랫폼입니다. 시작하자.

    앱을 배포하기 전에 몇 가지만 변경하면 됩니다.
  • index.js 파일에서 포트 8080을 process.env.PORT로 바꿉니다.http.listen(process.env.PORT)
  • 루트 디렉토리에 Procfile이라는 파일을 만들고 그 안에 다음을 작성합니다.web: node index.js
  • 또한 .gitignore 파일을 만들고 다음을 추가합니다./node_modules


  • 다음으로 터미널에서 루트 디렉토리를 열고 heroku cli를 설정합니다.heroku login로그인하라는 메시지가 표시됩니다. 자격 증명을 입력하면 준비가 완료됩니다.
  • 이제 heroku 앱을 만듭니다. heroku create <your-app-name-here>
  • 이제 git을 초기화하고 모든 것을 heroku 마스터에 커밋합니다.

  • git init
    git add .
    git commit -m "Initial Commit"
    git push heroku master
    

    완료될 때까지 기다리십시오. 생성된 URL로 이동하면 이전과 동일한 메시지를 볼 수 있습니다.

    참고: 생성될 자신의 URL을 사용하십시오.


    Flutter(클라이언트 측)



    이제 백엔드 부분이 완성되었으며 이제 Flutter에서 채팅 앱을 만들기 시작할 때입니다.

    터미널을 열고 다음 명령을 입력하여 Flutter 앱을 만듭니다.
    flutter create --androidx real_chat_flutter
    프로젝트가 생성된 후 IDE에서 폴더를 엽니다.

    pubspec.yaml 파일에서 다음 종속성을 추가합니다.

    dependencies:
      flutter:
        sdk: flutter
      cupertino_icons: ^0.1.2
      flutter_socket_io: ^0.6.0  //Add this dependency
    

    lib 폴더에서 main.dart를 열고 모든 코드를 삭제하고 다음 코드를 추가합니다.

    import 'package:flutter/material.dart';
    import './ChatPage.dart';
    
    void main() => runApp(MyMaterial());
    
    class MyMaterial extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          debugShowCheckedModeBanner: false,
          home: ChatPage(),
        );
      }
    }
    

    이제 ChatPage를 만들어야 합니다. lib 폴더 안에 ChatPage.dart 파일을 생성합니다. 채팅 페이지의 코드를 작성해 보겠습니다.

    import 'dart:convert';
    
    import 'package:flutter/material.dart';
    import 'package:flutter_socket_io/flutter_socket_io.dart';
    import 'package:flutter_socket_io/socket_io_manager.dart';
    
    class ChatPage extends StatefulWidget {
      @override
      _ChatPageState createState() => _ChatPageState();
    }
    
    class _ChatPageState extends State<ChatPage> {
      SocketIO socketIO;
      List<String> messages;
      double height, width;
      TextEditingController textController;
      ScrollController scrollController;
    
      @override
      void initState() {
        //Initializing the message list
        messages = List<String>();
        //Initializing the TextEditingController and ScrollController
        textController = TextEditingController();
        scrollController = ScrollController();
        //Creating the socket
        socketIO = SocketIOManager().createSocketIO(
          '<ENTER THE URL OF YOUR DEPLOYED APP>',
          '/',
        );
        //Call init before doing anything with socket
        socketIO.init();
        //Subscribe to an event to listen to
        socketIO.subscribe('receive_message', (jsonData) {
          //Convert the JSON data received into a Map
          Map<String, dynamic> data = json.decode(jsonData);
          this.setState(() => messages.add(data['message']));
          scrollController.animateTo(
            scrollController.position.maxScrollExtent,
            duration: Duration(milliseconds: 600),
            curve: Curves.ease,
          );
        });
        //Connect to the socket
        socketIO.connect();
        super.initState();
      }
    
      Widget buildSingleMessage(int index) {
        return Container(
          alignment: Alignment.centerLeft,
          child: Container(
            padding: const EdgeInsets.all(20.0),
            margin: const EdgeInsets.only(bottom: 20.0, left: 20.0),
            decoration: BoxDecoration(
              color: Colors.deepPurple,
              borderRadius: BorderRadius.circular(20.0),
            ),
            child: Text(
              messages[index],
              style: TextStyle(color: Colors.white, fontSize: 15.0),
            ),
          ),
        );
      }
    
      Widget buildMessageList() {
        return Container(
          height: height * 0.8,
          width: width,
          child: ListView.builder(
            controller: scrollController,
            itemCount: messages.length,
            itemBuilder: (BuildContext context, int index) {
              return buildSingleMessage(index);
            },
          ),
        );
      }
    
      Widget buildChatInput() {
        return Container(
          width: width * 0.7,
          padding: const EdgeInsets.all(2.0),
          margin: const EdgeInsets.only(left: 40.0),
          child: TextField(
            decoration: InputDecoration.collapsed(
              hintText: 'Send a message...',
            ),
            controller: textController,
          ),
        );
      }
    
      Widget buildSendButton() {
        return FloatingActionButton(
          backgroundColor: Colors.deepPurple,
          onPressed: () {
            //Check if the textfield has text or not
            if (textController.text.isNotEmpty) {
              //Send the message as JSON data to send_message event
              socketIO.sendMessage(
                  'send_message', json.encode({'message': textController.text}));
              //Add the message to the list
              this.setState(() => messages.add(textController.text));
              textController.text = '';
              //Scrolldown the list to show the latest message
              scrollController.animateTo(
                scrollController.position.maxScrollExtent,
                duration: Duration(milliseconds: 600),
                curve: Curves.ease,
              );
            }
          },
          child: Icon(
            Icons.send,
            size: 30,
          ),
        );
      }
    
      Widget buildInputArea() {
        return Container(
          height: height * 0.1,
          width: width,
          child: Row(
            children: <Widget>[
              buildChatInput(),
              buildSendButton(),
            ],
          ),
        );
      }
    
      @override
      Widget build(BuildContext context) {
        height = MediaQuery.of(context).size.height;
        width = MediaQuery.of(context).size.width;
        return Scaffold(
          body: SingleChildScrollView(
            child: Column(
              children: <Widget>[
                SizedBox(height: height * 0.1),
                buildMessageList(),
                buildInputArea(),
              ],
            ),
          ),
        );
      }
    }
    

    이제 두 기기에서 앱을 실행하고 주고받으며 채팅하세요😄.

    문제가 발생하면 내 github repo를 확인할 수 있습니다.


    ibtesam123 / real_chat_node








    ibtesam123 / real_chat_flutter





    기사가 마음에 든다면 별표 ⭐ 레포와 박수 👏를 잊지 마세요. 궁금하신 사항은 댓글로 물어보시면 됩니다. 감사합니다😄

    좋은 웹페이지 즐겨찾기