# react-native webview

# rn 프로젝트 및 웹 뷰 라이브러리 설치

// 프로젝트 생성
npx react-native init project-name

// 실행
npx react-native run-ios

// npm 다운로드시 해야하는 설정
npm install react-native-webview

// already link 확인
react-native link react-native-webview

// RNCWebview not found 같이 node_module을 못읽는 에러 발생시 ios node_module 설치 안했기 때문
cd ios
pod install

//위 명령어 실행 후 재시작하면 에러가 안뜬다
npx react-native run-ios

// pod not found 에러시
sudo gem cocopod

pod install

# rn에 webview 추가하기

이후 포스팅에서 firebase cloud message를 추가할 것입니다. fcm은 프로젝트의 가장 최상단 (App.js)에 위치해야만 한다고 docs에 있습니다. 그러므로 webview는 app.js의 하위 컴포넌트에서 구성하겠습니다.

//App.js
const App = () => {
  // 웹뷰와 rn과의 소통은 아래의 ref 값을 이용하여 이루어집니다.
  let webviewRef = useRef();

  /** 웹뷰 ref */
  const handleSetRef = _ref => {
    webviewRef = _ref;
  };

  /** webview 로딩 완료시 */
  const handleEndLoading = e => {
    console.log("handleEndLoading");
    /** rn에서 웹뷰로 정보를 보내는 메소드 */
    webviewRef.postMessage("로딩 완료시 webview로 정보를 보내는 곳");
  };

  return (
    <WebviewContainer
      webviewRef={webviewRef}
      handleSetRef={handleSetRef}
      handleEndLoading={handleEndLoading}
    />
  );
};
import { WebView } from "react-native-webview";

const WebviewContainer = ({ handleSetRef, handleEndLoading }) => {
  const url = "localhost:3000";

  /** 웹뷰에서 rn으로 값을 보낼때 거치는 함수 */
  const handleOnMessage = ({ nativeEvent: { data } }) => {
    // data에 웹뷰에서 보낸 값이 들어옵니다.
    console.log(data);
  };

  return (
    <WebView
      onLoadEnd={handleEndLoading}
      onMessage={handleOnMessage}
      ref={handleSetRef}
      source={{ uri }}
    />
  );
};

# 웹뷰에서 rn으로 데이터 송신

웹뷰 -> rn으로 데이터를 보내는 예시입니다. 노트북, 컴퓨터로 접속하는 웹에는 없지만 모바일로 웹에 접속하면 해당 웹에는 ReactNativeWebView 객체가 생성됩니다. 이 객체를 이용하면 rn에게 데이터를 전달할 수 있습니다.

# 예시

const requestPermission = () => {
  if (window.ReactNativeWebView) {
    // 모바일이라면 모바일의 카메라 권한을 물어보는 액션을 전달합니다.
    window.ReactNativeWebView.postMessage(
      JSON.stringify({ type: "REQ_CAMERA_PERMISSION" })
    );
  } else {
    // 모바일이 아니라면 모바일 아님을 alert로 띄웁니다.
    alert({ message: ERROR_TYPES.notMobile });
  }
};

위처럼 webview에 함수를 만들고 requestPermission함수를 실행하면, 우리가 rn에서 정의한 onMessage 메소드에 넣어준 함수가 실행됩니다.

/** 웹뷰에서 rn으로 값을 보낼때 거치는 함수 */
const handleOnMessage = ({ nativeEvent: { data } }) => {
  console.log(data); // { type: "REQ_CAMERA_PERMISSION" }
};

# rn에서 webview로 데이터 송신

다음은 rn -> webview로 데이터를 보내는 예시입니다. rn에서는 webviewRef.postMessage({type: TOKEN, data: xxxxx});를 이용하여 webview로 데이터를 전송합니다.

위 함수를 이용해 전송하면 웹뷰에서는 웹뷰 프로젝트의 최상단에 rn 정보를 listen한다는 함수를 실행합니다. react-router를 사용한 예시는 아래와 같습니다.

// routes.js
export default function Routes() {
  return (
    <Router>
      <RNListener>
      <Switch>
        ...
      </Switch>
    </Router>
  )
}

위처럼 어느 라우트에서든 RNListener가 실행되도록 만들어줍니다, 다음으로 RNListener입니다. rn에서 webviewRef.postMessage({type: TOKEN, data: xxxxx});으로 전송을 보냈다고 가정한다면

const RNListener = () => {
  /** react native 환경에서만 가능 */
  const listener = event => {
    const { data, type } = JSON.parse(event.data);
    if (type === "TOKEN") {
      // type이 TOKEN이기 때문에 이곳에 콘솔이 찍히게 됩니다.
      console.log(data) // xxxxx
      ...
    } else if (type === "NOTIFICATION") {
      ...
    }
  };

  if (window.ReactNativeWebView) {
    /** android */
    document.addEventListener("message", listener);
    /** ios */
    window.addEventListener("message", listener);
  } else {
    // 모바일이 아니라면 모바일 아님을 alert로 띄웁니다.
    alert({ message: ERROR_TYPES.notMobile });
  }
};

주의 사항은 rn을 듣는 listener 함수가 android와 ios가 다름을 인지하고 확실히 분기처리 해야합니다.

# ios webview console 띄우기

시뮬레이터를 이용하여 rn을 띄울경우 시뮬레이터에서 콘솔 및 네트워크를 보는 방법입니다.

사파리 → 환경설정 → 고급 → 메뉴 막대에서 개발자용 메뉴보기

앱 실행하고 시뮬레이트 띄운 다음 → 탑 메뉴에서 → 개발자용 → 시뮬레이터에서 현재 띄운 앱 이름 클릭 → 웹과 동일하게 디버깅 가능

Last Updated: 3/24/2021, 8:55:12 PM