WebView는 앱 안에 웹 페이지를 임베딩하는 컴포넌트입니다. 결제, 약관, 외부 콘텐츠 표시 등에 자주 사용됩니다.


기본 사용

BASH
npm install react-native-webview
TSX
import { WebView } from 'react-native-webview';

function WebViewScreen() {
  return (
    <WebView
      source={{ uri: 'https://example.com' }}
      style={{ flex: 1 }}
      // 로딩 인디케이터
      startInLoadingState
      renderLoading={() => <ActivityIndicator style={{ flex: 1 }} />}
      // 에러 처리
      renderError={(errorName) => (
        <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
          <Text>페이지를 불러올 수 없습니다</Text>
        </View>
      )}
    />
  );
}

네이티브 → 웹 통신

TSX
import { useRef } from 'react';
import { WebView } from 'react-native-webview';

function NativeToWeb() {
  const webViewRef = useRef<WebView>(null);

  // 네이티브에서 웹으로 데이터 전송
  const sendToWeb = (data: any) => {
    const script = `
      window.receiveFromNative(${JSON.stringify(data)});
      true; // iOS에서 필수
    `;
    webViewRef.current?.injectJavaScript(script);
  };

  return (
    <View style={{ flex: 1 }}>
      <WebView
        ref={webViewRef}
        source={{ uri: 'https://mywebapp.com' }}
      />
      <Pressable onPress={() => sendToWeb({ token: 'abc', userId: '123' })}>
        <Text>데이터 전송</Text>
      </Pressable>
    </View>
  );
}

// 웹 측 코드
// window.receiveFromNative = function(data) {
//   console.log('네이티브에서 받은 데이터:', data);
// };

웹 → 네이티브 통신

TSX
function WebToNative() {
  const handleMessage = (event: WebViewMessageEvent) => {
    try {
      const data = JSON.parse(event.nativeEvent.data);

      switch (data.type) {
        case 'PAYMENT_COMPLETE':
          handlePaymentComplete(data.payload);
          break;
        case 'NAVIGATE':
          navigation.navigate(data.screen, data.params);
          break;
        case 'CLOSE':
          navigation.goBack();
          break;
      }
    } catch (error) {
      console.error('메시지 파싱 에러:', error);
    }
  };

  return (
    <WebView
      source={{ uri: 'https://payment.example.com' }}
      onMessage={handleMessage}
      // injectedJavaScript로 웹에 브릿지 함수 주입
      injectedJavaScript={`
        window.sendToNative = function(type, payload) {
          window.ReactNativeWebView.postMessage(
            JSON.stringify({ type, payload })
          );
        };
        true;
      `}
    />
  );
}

// 웹 측 코드
// 결제 완료 시:
// window.sendToNative('PAYMENT_COMPLETE', { orderId: '123', amount: 50000 });

결제 모듈 연동 패턴

TSX
function PaymentWebView({ orderId, amount }: {
  orderId: string;
  amount: number;
}) {
  const webViewRef = useRef<WebView>(null);

  // 결제 페이지 URL에 파라미터 전달
  const paymentUrl = `https://payment.example.com?orderId=${orderId}&amount=${amount}`;

  const handleMessage = (event: WebViewMessageEvent) => {
    const data = JSON.parse(event.nativeEvent.data);

    if (data.type === 'PAYMENT_SUCCESS') {
      Alert.alert('결제 완료', `주문번호: ${data.orderId}`);
      navigation.navigate('OrderComplete', { orderId: data.orderId });
    } else if (data.type === 'PAYMENT_FAIL') {
      Alert.alert('결제 실패', data.message);
    } else if (data.type === 'PAYMENT_CANCEL') {
      navigation.goBack();
    }
  };

  return (
    <WebView
      ref={webViewRef}
      source={{ uri: paymentUrl }}
      onMessage={handleMessage}
      // 결제 관련 설정
      javaScriptEnabled={true}
      domStorageEnabled={true}
      // 외부 (카카오페이 ) 이동 허용
      originWhitelist={['*']}
      onShouldStartLoadWithRequest={(request) => {
        // 외부 앱 스킴 처리
        if (request.url.startsWith('kakaopay://') ||
            request.url.startsWith('intent://')) {
          Linking.openURL(request.url);
          return false;
        }
        return true;
      }}
    />
  );
}

보안 주의사항

TSX
<WebView
  // 신뢰할 수 있는 도메인만 허용
  originWhitelist={['https://myapp.com', 'https://payment.example.com']}

  // 파일 접근 차단
  allowFileAccess={false}

  // 콘텐츠 보안 정책
  injectedJavaScript={`
    // 민감한 정보를 window 객체에 노출하지 않기
    delete window.ReactNativeWebView;
    true;
  `}
/>

정리

  • **네이티브→웹 **: injectJavaScript로 JS 코드를 실행합니다
  • ** 웹→네이티브 **: window.ReactNativeWebView.postMessageonMessage를 사용합니다
  • 결제 모듈 연동 시 ** 외부 앱 스킴 처리 **(onShouldStartLoadWithRequest)가 필수입니다
  • 메시지는 JSON 문자열 로 주고받고, type 필드로 메시지 종류를 구분하세요
  • 보안 을 위해 신뢰할 수 있는 도메인만 허용하세요
댓글 로딩 중...