[안드로이드] socket.io를 이용한 간단한 채팅 어플 만들어보기 (1)

동현·2021년 2월 10일
5
post-thumbnail

최근에 했던 연합동아리 활동에서 채팅 어플을 만든 적이 있었는데 시간에 쫓겨서 그런지 코드도 깔끔하지 못했고 여러 아쉬운 점이 많아 정리해보는 겸 간단한 채팅 어플을 만들어보기로 하였다. 연합 동아리에서 했던 프로젝트에서는 서버 담당자분이 따로 있었는데, 이번에는 Node.js로 간단한 서버를 구축해서 직접 만들어볼 생각이다.

1. Node.js 서버 세팅

서버 폴더를 만들고 npm init을 통해 프로젝트 세팅을 하고 간단한 http 서버를 만들었다.

const express = require('express')
const http = require('http')
const app = express()
const server = http.createServer(app)

server.listen(80, () => {
  console.log(`Server listening at http://localhost:80`)
})

포트의 경우 80 포트를 사용하였다. 이제 http 서버를 socket.io 서버로 업그레이드 시켜주면 된다.

const express = require('express')
const http = require('http')
const app = express()
const server = http.createServer(app)

const io = require('socket.io')(server)

io.sockets.on('connection', (socket) => {
  console.log(`Socket connected : ${socket.id}`)

  socket.on('disconnect', () => {
    console.log(`Socket disconnected : ${socket.id}`)
  })
})

server.listen(80, () => {
  console.log(`Server listening at http://localhost:80`)
})

간단하게 연결되었을 때와 연결을 해제했을 시의 이벤트만 작성해두었다.

2. 안드로이드 세팅

어플에 필요한 액티비티는 딱 두개만 사용하기로 생각했다.

  1. 유저이름과 들어갈 방 번호를 치는 MainActivity
  2. 실제 채팅을 할 ChatActivity

또한, 코드 작성의 편의성을 위해 뷰바인딩을 사용하였다.

따라서 MainActivity는 유저이름과 들어갈 방번호를 칠 수 있는 간단한 디자인으로 만들었다.

package com.dongchyeon.simplechatapp;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;

import com.dongchyeon.simplechatapp.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        initUI();
    }

    private void initUI() {
        binding.enterBtn.setOnClickListener(v -> {
            Intent intent = new Intent(getApplicationContext(), ChatActivity.class);
            intent.putExtra("username", binding.usernameEdit.getText().toString());
            intent.putExtra("roomNumber", binding.roomEdit.getText().toString());
            startActivity(intent);
        });
    }
}

MainActivity.java

메인액티비티 내의 코드도 위와 같이 간단하다. 입장 버튼을 누를 시 EditText내의 username과 roomNumber를 intent에 담아 ChatActivity에 넘겨주었다.

package com.dongchyeon.simplechatapp;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

import com.dongchyeon.simplechatapp.databinding.ActivityChatBinding;
import com.dongchyeon.simplechatapp.model.RoomData;
import com.google.gson.Gson;

import java.net.URISyntaxException;

import io.socket.client.IO;
import io.socket.client.Socket;

public class ChatActivity extends AppCompatActivity {
    private ActivityChatBinding binding;

    private Socket mSocket;
    private String username;
    private String roomNumber;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = ActivityChatBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        init();
    }

    private void init() {
        try {
            mSocket = IO.socket("http://10.0.2.2:80");
            Log.d("SOCKET", "Connection success : " + mSocket.id());
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }

        Intent intent = getIntent();
        username = intent.getStringExtra("username");
        roomNumber = intent.getStringExtra("roomNumber");

        mSocket.connect();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mSocket.disconnect();
    }
}

ChatActivity.java

ChatAcitivty에서는 액티비티가 생성될 때, MainActivity에서 넘어온 intent를 통해 username과 roomNumber를 알아냈고 서버와 연결해주었다. 반대로 액티비티가 소멸될 때는 연결을 해제해주었다.

서버를 작동시키고 에뮬레이터로 테스트해본 결과 성공적으로 서버와 연결되었다.

⚠ 서버와 연결이 안 된다면?

서버나 안드로이드나 코드를 분명 오류없이 짰다고 생각했었는데 서버쪽 로그에 소켓 연결이 되었다는 로그나 이런 것이 안 찍혀서 코드를 이것저것 뜯어 고쳐보았지만, 문제는 간단하였다. 바로 AndroidManifest.xml을 건드리면 되는 것이었다.

서버에 연결해야 하므로 인터넷 권한이 필요하다. 따라서 application 태그 위에 다음을 추가해주자.

<uses-permission android:name="android.permission.INTERNET" />

필자의 경우 이를 추가해주었는데도 불구하고 연결이 안됐었는데, 이를 찾아보니 안드로이드에서는 기본적으로 http 접근을 허용해주지 않기 때문이었다.

android:usesCleartextTraffic="true"

따라서 application 태그 안에 다음을 추가해 http 접근을 허용해줘야 했다.

3. 참조

npm, "socket.io", https://www.npmjs.com/package/socket.io

profile
https://github.com/DongChyeon

0개의 댓글