요즘 많은 어플리케이션을 사용하다보면, 사용자간의 소통을 위한 기능으로 채팅기능을 제공하고 있습니다.
실제로 현업에서 개발을 진행하다보면 채팅은 필수기능으로 꼽힐 정도로 사용자의 니즈가 많은 것 같습니다.

최근들어 제가 속해 있는 스타트업에서는, 채팅기능에 대한 사용자의 피드백과 필요성을 많이 느끼고 있음을 알고,
개발팀에서는 실제 본격적인 개발에 들어가기에 앞서, 채팅기능에 대한 검토와 프로토타이핑을 진행하고 있습니다.

요즘은 기술이 많이 발전하여 채팅을 구현한다고하면 socket통신 / mqtt / xmpp 등 많은 기술스택을 생각할 수 있지만,
저희는 현재 node.js를 이용하여 back-end를 개발해왔으며, npm의 module중 socket통신과 관련된 유명한 module인 socket.io를 이용해서 채팅을 구현해보기로 했습니다.
socket.io팀(?)에서는 다행히도 안드로이드에서 쉽게 socket.io를 사용할 수 있도록 라이브러리도 만들어두었습니다.

우선 본격적인 글을 시작하기에 앞서, 글 읽기 귀찮고 난 코드만 알려줘!라고 하시는분들을 위해 참고 URL부터 언급하고 시작하겠습니다.

참고 URL

의존성 추가

Android에서 라이브러리를 사용하기 위해, 제일 먼저 하는 작업은 역시나, gradle에 의존성을 추가해주는 일입니다.

1
2
3
compile ('io.socket:socket.io-client:1.0.0') {
exclude group: 'org.json', module: 'json'
}

의존성을 추가할 때, exclude group: 'org.json', module: 'json'를 해주지 않아도 사용에 문제는 없지만,
Android Studio의 로그창에 옛날 버전의 json 패키지를 제외처리했다는 warning 메시지를 볼 수 있으니, 추가하는 것이 좋습니다.

Socket 연결

Socket 통신을 사용할 Activity에서 다음과 같은 코드를 추가합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
private Socket mSocket;
@Override
protected void onCreate(Bundle savedInstanceState) {
// 설명의 편의를 위해 onCreate()메서드에 추가하였으나,
// 꼭 onCreate() 메서드에 위치할 필요는 없을 것 같습니다.
try {
mSocket = IO.socket("SERVER URL");
mSocket.connect();
} catch(URISyntaxException e) {
e.printStackTrace();
}
}

연결을 위한 코드는 단 2줄이면 가능합니다.
IO.socket("SERVER URL")를 이용하면 Socket객체를 얻을 수 있습니다.
이렇게 얻은 Socket객체를 통해 이벤트를 서버로 전송하거나 또는 서버로부터 이벤트를 전송받기 위해 계속적으로 들고 있어야하므로,
해당 Activity Class 상단에서 mSocket 변수를 선언하고, 해당 변수에 Socket객체를 저장해두시면 됩니다.

Event 전달 처리

Socket서버에 성공적으로 연결이 되면, 우리는 앞에서 얻은 Socket객체를 통해 이벤트를 서버로 전송하고,
서버로부터 전달받은 이벤트를 이용하여 여러가지 처리를 할 수 있습니다.

복잡하게 느껴질 수 있겠지만, 단 2가지만 기억하시면 됩니다.

  1. Socket.on(String event, Listener listener)
    • 첫번째 인자로 서버로부터 전달을 기다리는 이벤트명을 지정하고,
    • 두번째 인자로 해당 이벤트를 전달받은 후, 해당 Listener를 통해 Android에서 제어를 하면 됩니다.
  2. Socket.emit(String event, Object args)
    • 첫번째 인자로 서버로 전송할 이벤트명을 지정하고,
    • 두번째 인자로 추가적으로 전송할 데이터를 지정합니다. 대부분의 서버 - 클라이언트 통신은 JSON을 이용한 통신을 할 것이므로, JSONObject로 데이터를 생성한 후, 지정해주면 될 것 같습니다.

약간은 어렵게 느껴지실 수 있지만, 코드를 보면 바로 이해 될 듯 합니다.
우선은 서버로부터 전달받은 이벤트를 Android에서 처리하는 코드의 일부입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Override
protected void onCreate(Bundle savedInstanceState) {
// IO.socet()메서드와 mSocket.connect() 메서드사이에 일반적으로 작성하는 것 같습니다.
mSocket.on(Socket.EVENT_CONNECT, onConnect);
mSocket.on("chat-message", onMessageReceived);
}
// Socket서버에 connect 된 후, 서버로부터 전달받은 'Socket.EVENT_CONNECT' Event 처리.
private Emitter.Listener onConnect = new Emitter.Listener() {
@Override
public void call(Object... args) {
// your code...
}
};
// 서버로부터 전달받은 'chat-message' Event 처리.
private Emitter.Listener onMessageReceived = new Emitter.Listener() {
@Override
public void call(Object... args) {
// 전달받은 데이터는 아래와 같이 추출할 수 있습니다.
JSONObject receivedData = (JSONObject) args[0];
// your code...
}
};

생각보다 간단하지 않나요?
Android에서 서버로 이벤트를 전달하는 부분은 더 간결합니다. 코드로 확인해보시죠.

1
2
3
4
5
6
7
8
9
// 서버로 이벤트를 전송하는 부분에 적절히 추가하시면 될 것 같아요.
JSONObject data = new JSONObject();
try {
data.put("key1", "value1");
data.put("key2", "value2");
mSocket.emit('event-name', data);
} catch(JSONException e) {
e.printStackTrace();
}

Java에서 기본적으로 제공되는 JSONObject를 이용하여 데이터를 처리하기 위해서는 JSONException이 발생할 수 있으므로,
필수적으로 try - catch처리를 해주어야 합니다. 예외처리를 좋은 습관이라고 생각하지만,
이것마저 귀찮으시다면 JSONObject객체에서 제공하는 optXXX() 메서드를 이용하여 처리해 줄 수도 있습니다.

마무리

저도 실질적으로 프로토타이핑을 해보기 이전에는 Socket통신에 대해 막연한 생각이 있었습니다.
하지만 위에서 살펴보았듯, Socket.io 팀에서는 마치 안드로이드에서 사용할 것을 대비하여 Android용 Socket.io 라이브러리를 만들어주었고,
Socket 통신을 한번도 안해본 사람도 단 몇줄의 코드를 이용하여 Socket통신을 할 수 있도록 제공하고 있습니다.
생활코딩의 이고잉님의 몇몇 강좌에서 하시는 말씀인 프로그래밍하기 좋은 시대에 살고있다.라는 말을 요즘들어 더욱 체감하고 있는 것 같습니다.

위의 코드는 단순히 서버와 클라이언트간의 일회성 Socket통신을 하고 있지만,
적절한 이벤트 수/발신 타이밍에 DB나 Push 기능 등을 보강하면 그럴싸한 채팅프로그램을 만들 수 있을 것 같습니다.
기회가 된다면, DB나 Push 기능을 조금 더 보강한 그럴싸한 채팅프로그램으로 업데이트를 한 후, 공개하도록 하겠습니다!