회사에서 웹으로 만들어진 프로덕트를 앱으로 만들어야하는 일이 주어졌다.
유일한 프론트앤드 개발자.. CTO님과 머리를 굴렸다!
...
내가 React Native 경험도 있고 웹 프로덕트도 모바일 사이즈로 개발하였으니 React Native로 웹뷰 앱을 만들자 !
이런저런 이야기를 떠나서, WebView를 사용할 때 React Native 모듈이 아니면 실행되지 않는 문제가 있다.
예를 들어 웹뷰 내의 kakao channel link를 실행할 때 android의 intent::로 인해 실행 실패 등등..
웹뷰와 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 실행'
})
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 ➡️ 웹뷰 이벤트 보내기를 다뤄볼 것이다.