[React native]  실시간 알림
개발

[React native] 실시간 알림

작성일: 2023년 10월 18일

현재 진행중인 knockknock 프로젝트의 알림 기능 구현을 위해 서버의 데이터를 실시간으로 스트리밍하면서 알림 데이터를 받아올 수 있는 방법에 대해 찾아봤다.

Rest API

클라이언트에서 HTTP 요청이 있을 때 서버는 요청에 대한 데이터를 전송하고 즉시 종료되는 클라이언트에서만 서버로 연결되는 단방향 통신이다.

  • 사용처: 게시판 CRUD, 회원정보, 상품 정보 등
  • WebSocket

    TCP/IP 또는 UDP/IP와 같은 기존의 네트워크 프로토콜을 사용하는 Socket과 달리 HTTP를 기반으로 하며, 웹 브라우저와 웹 서버 간에 웹소켓 프로토콜을 사용하여 연결을 설정하는 양방향 통신이다.

  • 사용처: 채팅 서비스, 스트리밍 서비스, 실시간 차트 등
  • SSE(Server-Sent-Event)

    버의 데이터를 클라이언트에서 실시간으로 스트리밍할 수 있도록 연결을 유지하는 단방향 통신이다. HTTP 프로토콜 위에서 동작하며 실행 시 기존의 HTTP 연결을 유지한 상태에서 리커넥팅이나 추가설정 없이 변경된 데이터를 지속적으로 수신할 수 있다.

  • 사용처: 알림, 중계 등
  • React-native-sse

    알림 기능 구현을 위해 React native에서 사용 가능하고 엑세스 토큰 전송을 위한 커스텀 헤더 설정이 가능한 React-native-sse를 선택했다.

    import React, {useEffect} from 'react';
    import EventSource, {EventSourceListener} from 'react-native-sse';
    
    const Notifications: React.FC= () => {
      
      //...
      
    useEffect(() => {
      // 커스텀 헤더 옵션
        const option = {
          method: 'GET', // GET은 Defualt
          headers: {Authorization: `Bearer ${token}`},
          debug: true, // 요청을 디버깅하는 옵션
        };
      // 종속형 배열에 빈배열을 전달하여 컴포넌트의 첫 랜더링 시 실행
        const eventSource = new EventSource(streamUrl, option);
      
      	// 요청 후 응답에 따른 동작을 순수함수에 담았다.
        const listener: EventSourceListener = event => {
          if (event.type === 'open') {
            console.log('Open SSE connection.');
          } else if (event.type === 'message') {
            console.log('Connection', event);
          } else if (event.type === 'error') {
            console.error('Connection error:', event.message);
          } else if (event.type === 'exception') {
            console.error('Error:', event.message, event.error);
          }
        };
      // 이벤트리스너를 호출
        eventSource.addEventListener('open', listener);
        eventSource.addEventListener('message', listener);
        eventSource.addEventListener('error', listener);
      
      // 컴포넌트의 언마운트와 함께 연결이 종료된다.
        return () => {
          eventSource.removeAllEventListeners();
          eventSource.close();
        };
      }, []);
    }
      
      //...
      

    첫 연결 시도 시 Android 시뮬레이터에서 테스트 시 유효한 URL과 Token을 전달해도 401에러를 반환했다. 구글링 결과 안드로이드에 내장된 Flipper(모바일 에플리케이션 개발 시 디버깅을 위한 도구)에서 네트워크의 요청과 응답을 모니터링하는 NetworkFlipperPlugin 플러그인이 실행된다. 이 디버깅 과정 중에 SSE 요청을 가로채어 실시간 요청에 개입하여 발생한 문제로 아래의 코드를 주석처리하니 정상적으로 연결됐다.

    public class ReactNativeFlipper {
      public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
        if (FlipperUtils.shouldEnableFlipper(context)) {
          final FlipperClient client = AndroidFlipperClient.getInstance(context);
    
          client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
          client.addPlugin(new DatabasesFlipperPlugin(context));
          client.addPlugin(new SharedPreferencesFlipperPlugin(context));
          client.addPlugin(CrashReporterPlugin.getInstance());
    
          // NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
          // NetworkingModule.setCustomClientBuilder(
          //     new NetworkingModule.CustomClientBuilder() {
          //       @Override
          //       public void apply(OkHttpClient.Builder builder) {
          //         builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
          //       }
          //     });
          // client.addPlugin(networkFlipperPlugin);
          client.start();
    - 참고