# react-native webview

  • react-native 버전은 "0.73.2", react-native-webview 버전은 "^13.8.6"입니다.

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

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

// 실행
npx react-native run-ios

// npm 다운로드시 해야하는 설정
npm install 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 추가하기

  • 중요한 부분은 useRef를 이용하여 webview를 ref로 잡는 부분입니다.
  • ref를 잡은 변수를 이용하여 rn과 webview간 통신을 합니다.
import { useRef, useState } from "react";
import { WebView, WebViewMessageEvent } from "react-native-webview";

const Index = () => {
  const webviewRef = useRef<any>();

  // rn에서 웹뷰로 변수 호출
  const handleEndLoading = (loadingState: string) => {
    if (!webviewRef) return;
    console.log("handleEndLoading");
    /** rn에서 웹뷰로 정보를 보내는 메소드 */
    webviewRef.current.postMessage(
      JSON.stringify({ type: "LOADING", data: loadingState })
    );
  };

  const handleIsApp = () => {
    if (!webviewRef) return;
    webviewRef.current.postMessage(
      JSON.stringify({ type: "IS_APP", data: "true" })
    );
  };

  // 웹뷰에서 rn으로 함수 또는 변수 호출
  const onMessageFromWebView = ({ nativeEvent }: WebViewMessageEvent) => {
    const { type, data } = JSON.parse(nativeEvent.data);
    console.log(type, data);

    if (type === "goBack") {
      navigation.goBack();
    } else if (type === "title") {
      setTitle(data);
    } else if (type === "share") {
      setShare(data);
    }
  };

  return (
    <WebView
      bounces={false}
      // 웹뷰가 앱에 맨 처음 load 시작 되는 함수
      onLoadStart={() => {
        handleEndLoading("start");
      }}
      // 웹뷰가 앱에 맨 처음 load 종료 될때 트리거 되는 함수
      onLoadEnd={() => {
        handleEndLoading("end");
        handleIsApp();
      }}
      onMessage={onMessageFromWebView}
      ref={webviewRef}
      source={{ uri: `웹뷰 url` }}
    />
  );
};

# webview 로직

  • 아래 로직은 webview가 띄워질때 웹에서 띄워진건지, 앱을 통한건지 구분하는 로직을 포함합니다.
  • 중요하게 봐야할 곳은 android, ios에서 들어오는 webview를 불러오는 객체가 달라 구분해야한다는 점입니다.
"use client";
import React, { useEffect, useState } from "react";
import styled, { css } from "styled-components";
import ContentNext from "../../../../../public/icons/content-next.svg";
import { Swiper, SwiperSlide } from "swiper/react";
import "swiper/css";
import "swiper/css/pagination";
import "swiper/css/navigation";
import { Pagination, Navigation } from "swiper/modules";

const Page = ({ params }: { params: { page: string } }) => {
  const [msg, setMsg] = useState<{ type: string; data: string } | null>(null);
  const [isApp, setIsApp] = useState(false);

  // rn에서 Webview로 보낸 값을 수신하는 함수
  const listener = (event: any) => {
    console.log("webview listener", event.data);
    const appData = JSON.parse(event.data);
    if (appData.type === "LOADING") {
      setMsg(JSON.parse(event.data));
    } else if (appData.type === "IS_APP") {
      setIsApp(true);
    }
  };

  useEffect(() => {
    // android, ios 구분하는 코드
    const receiver = navigator.userAgent.includes("Android")
      ? document
      : window;
    receiver.addEventListener("message", listener);
    postMessage("title", "상단 타이틀에 올 값입니다.");
    postMessage("share", true);
  }, []);

  // webview에서 rn으로 값을 송신하는 함수
  const postMessage = (type: string, data: any) => {
    if (!window.ReactNativeWebView) {
      // 이 값이 없는 경우 모바일이 아니다.
      return;
    }
    window.ReactNativeWebView?.postMessage(JSON.stringify({ type, data }));
  };

  return (
    <Container>
      {isApp ? (
        <>
          {msg && msg.data === "end" && (
            <>앱내에 띄워진 웹뷰가 로딩이 완료되면 실행되는 곳</>
          )}
        </>
      ) : (
        <>모바일 웹에서 띄워지는 웹뷰 영역</>
      )}
    </Container>
  );
};

# ios webview console 띄우기

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

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

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

#react-native #react
노경환
이 글이 도움이 되셨다면! 깃헙 스타 부탁드립니다 😊😄
최근변경일: 4/27/2024, 7:12:59 AM