React Native로 웹뷰 앱 배포하기 - 1. 웹뷰 ➡️ React Native 이벤트 보내기

Jiwoo JEONG·2022년 8월 4일
2

React Native WebView

목록 보기
1/2
post-thumbnail

React Native와 React Native WebView 간의 이벤트 송수신 (1편. 웹뷰 ➡️ React Native 이벤트 보내기)

나에게 주어진 과제

회사에서 웹으로 만들어진 프로덕트를 앱으로 만들어야하는 일이 주어졌다.
유일한 프론트앤드 개발자.. CTO님과 머리를 굴렸다!
...
내가 React Native 경험도 있고 웹 프로덕트도 모바일 사이즈로 개발하였으니 React Native로 웹뷰 앱을 만들자 !

오늘 이야기할 것

이런저런 이야기를 떠나서, WebView를 사용할 때 React Native 모듈이 아니면 실행되지 않는 문제가 있다.
예를 들어 웹뷰 내의 kakao channel link를 실행할 때 android의 intent::로 인해 실행 실패 등등..

그래서 React Native 모듈을 사용할 때 어떠한 방식으로 웹뷰에서 이벤트를 쏘았고, React Native에서는 어떻게 처리했는지에 대해 블로깅을 해보고자한다!

즉, React Native와 웹뷰 간의 이벤트 기반 핸들링!

WebViewEventPropsType

웹뷰와 React Native에서 동일한 interface를 사용하기 위해 아래와 같은 type을 만들었다.

interface WebViewEventPropsType<T = any> {
  event: string; // 약속된 Event명
  data?: T; // data가 필요한 경우가 있다
}

웹뷰 내의 이벤트 보내기

약속 된 이벤트명들은 Enum으로 만들었다
예를 들어, 가장 간단히 React Native의 개발 모드에서 console을 보고 싶은 경우.

enum RNEventEnum {
  	ConsoleLog = 'CONSOLE_LOG'
}

그리고 React Native로 event를 보내는 util
❌ 주의할 점은 꼭 JSON.stringify해서 보내야한다는 것 ❌

export const sendEvent = (data: RNEventPropsType<any, RNEventEnum>) => {
  if (window && window.ReactNativeWebView) {
  	window.ReactNativeWebView.postMessage(JSON.stringify(data));
  }
};

그래서 합쳐진 React Native로 console.log를 찍는 event인 ConsoleLog를 보내는 코드는 다음과 같다.

sendEvent({
	event: RNEventEnum.ConsoleLog
    data: 'console log event 실행'
})

React Native에서 이벤트 받기

  • 웹뷰 이벤트를 핸들링할 custom hook을 작성하였다.
  • WebViewEventHandlerType은 웹뷰에서 작성한 event명에 따라 핸들링 함수를 실행하기 위해 다음과 같이 작성하였다.
  • WEB_VIEW_REF를 사용한 이유는 WEB_VIEW에서 사용하는(현재 예시 코드에는 없지만) navigation, window와 같은 다른 객체의 변화에 따라 값을 변경해주고 싶어서이다.
interface WebViewEventHandlerType<T = any> {
  [index: string]: (props?: WebViewEventPropsType<T>) => void;
}

const useWebViewEvent = (webViewRef: RefObject<WebView>) => {
  const handleConsoleLog = (props?: WebViewEventPropsType<any>) => {
      console.log(props?.data);
    };
     const WEB_VIEW_EVENT: WebViewEventHandlerType = {
     	CONSOLE_LOG: handleConsoleLog,
     }
       const WEB_VIEW_EVENT_REF = useRef(WEB_VIEW_EVENT);

  useEffect(() => {
    WEB_VIEW_EVENT_REF.current = WEB_VIEW_EVENT;
  });
  return WEB_VIEW_EVENT_REF;
  }

React Native Webview에서 onMessage props를 다음과 같이 넘겼다.
❌주의사항❌ + 여담
나는 if (webViewEvent.current[parsed.event]) { webViewEvent.current[parsed.event](parsed); }를 처음에 적지 않아 앱 심사 완료, 배포 이후 앱 크래시가 나는 엄청난 상황을 겪었다.. 정말 멘탈이 터진 7월 1일.. 아직 기억한다 😭 회사분들이 괜찮냐고 여럿 전화를 주시고 10시까지 야근을 했던 기억...😔😔
다행히 Deep Link와 FCM에 관련한 event 처리를 하지 않았던 것이라 두 가지의 사용을 미루고 웹에서 두 가지 event를 보내지 않는 것으로 급한 불을 껐다. 이후 앱을 재심사 받고, 유저들 중 60%가 재심사 받은 버전을 다운 받기를 기다리고 다시 웹에서 두 가지 event를 보냈다....

  const onMessage = (e: WebViewMessageEvent) => {
    const { data } = e.nativeEvent;
    if (data !== 'undefined') {
      const parsed: WebViewEventPropsType<any> | undefined = JSON.parse(data);
      if (parsed) {
          if (webViewEvent.current[parsed.event]) {
            webViewEvent.current[parsed.event](parsed);
          }
      }
    }
  };

마무리

이러면 React Native와 웹뷰 간의 약속한 event명 기반의 핸들링이 완성된다.
두 개 간의 Message가 송수신이 가능한 것을 보고 이전 서비스에서 FCM 처리를 event명 기반으로 했던 것이 떠올라 다음과 같은 컨셉으로 이벤트 처리를 해보았다.

2편에서는 React Native ➡️ 웹뷰 이벤트 보내기를 다뤄볼 것이다.

Reference

React Native Webview

profile
FE Developer as Efficiency Maker

0개의 댓글