본문 바로가기
📁 프론트엔드/React

React 웹뷰에서 AppsFlyer URL 받기, 브릿지 구현기 정리!

by d0bby 2025. 4. 7.

최근 프로젝트에서 웹뷰 안의 React 페이지에서 AppsFlyer URL을 앱으로부터 전달받아야 하는 요구사항이 있었습니다.
이걸 해결하기 위해 사용한 기술이 바로 '브릿지(Bridge)'였는데요.

 

처음 접했을 땐 막막했지만, 원리를 이해하고 나니 생각보다 단순했습니다.
오늘은 그 과정을 정리하며 브릿지가 무엇이고, 왜 필요한지, 어떻게 사용하는지 공유해보려 합니다.

 


 

브릿지란 무엇일까요?

브릿지(Bridge)는 말 그대로 두 환경을 연결해주는 다리 역할을 합니다.
앱(Native)과 웹(Web)은 기본적으로 서로 다른 세계에서 작동하기 때문에 직접적으로 통신하기 어렵습니다.
하지만 브릿지를 활용하면 웹에서 앱의 기능을 호출하거나, 반대로 앱에서 웹으로 데이터를 넘겨주는 게 가능해집니다.

 


 

왜 브릿지가 필요했을까요?

이번 프로젝트에서는 클라이언트 앱에서 만들어둔 AppsFlyer URL을 웹뷰 안에서 사용해야 했어요.
그런데 이 URL은 앱에서만 접근 가능한 값이기 때문에, 웹 단에서는 직접 가져올 수 없는 구조였습니다.

결국 앱에서 이 URL을 웹으로 전달해주는 통로가 필요했고, 그 역할을 브릿지가 해주게 된 거죠.

 


 

어떻게 구현했을까요?

React 환경에서는 웹뷰를 ReactNativeWebView 같은 컴포넌트로 띄우는 방식으로 사용합니다.
이때 앱에서 웹으로 데이터를 전달하려면 보통 postMessage를 사용하는데요.

 

1. 앱(Native) → 웹 : postMessage로 데이터 보내기

앱(Native) 쪽에서는 아래와 같이 메시지를 전달합니다.
(React Native 기준 예시입니다.)

// Native(Android/iOS) 앱 코드
webViewRef.postMessage(JSON.stringify({
  appsFlyerUrl: 'https://example.onelink.me/abc/123456',
}));

 

 

2. 웹(React) → 메시지 수신하기

웹뷰 안의 React 페이지에서는 message 이벤트를 수신하여 데이터를 처리할 수 있습니다.

useEffect(() => {
  const handleMessage = (event: MessageEvent) => {
    try {
      const data = JSON.parse(event.data);
      if (data.appsFlyerUrl) {
        console.log('앱에서 받은 URL:', data.appsFlyerUrl);
        // 이후 필요한 로직 처리
      }
    } catch (err) {
      console.error('메시지 파싱 오류:', err);
    }
  };

  window.addEventListener('message', handleMessage);
  return () => {
    window.removeEventListener('message', handleMessage);
  };
}, []);

 

 

3. 웹 → 앱 : 준비 완료 메시지 보내기 (선택적)

앱이 너무 빠르게 메시지를 보내면 웹이 아직 준비되지 않아 놓치는 경우가 생길 수 있어요.
이럴 때는 웹이 먼저 "준비 완료" 메시지를 앱에 보내고,
앱은 그 이후에 데이터를 전달하도록 구현하면 안정적입니다.

useEffect(() => {
  // 웹 페이지 로딩 완료 후 앱에 신호 보내기
  if (window.ReactNativeWebView?.postMessage) {
    window.ReactNativeWebView.postMessage(JSON.stringify({ ready: true }));
  }
}, []);

 

이 코드는 웹뷰 페이지가 마운트될 때 한 번 실행되며, 앱에 "ready": true 메시지를 보냅니다.

 

앱은 이 메시지를 수신한 뒤에만 데이터를 보내도록 처리하면,
웹 쪽에서 메시지를 놓치는 경우를 방지할 수 있어요.

 

전체 코드 예시:

import { useEffect } from 'react';

function WebViewPage() {
  useEffect(() => {
    // 1. 앱에게 준비 완료 메시지 보내기
    if (window.ReactNativeWebView?.postMessage) {
      window.ReactNativeWebView.postMessage(JSON.stringify({ ready: true }));
    }

    // 2. 앱에서 메시지 받기
    const handleMessage = (event: MessageEvent) => {
      try {
        const data = JSON.parse(event.data);
        if (data.appsFlyerUrl) {
          console.log('앱에서 받은 URL:', data.appsFlyerUrl);
          // 필요한 로직 처리
        }
      } catch (err) {
        console.error('메시지 파싱 오류:', err);
      }
    };

    window.addEventListener('message', handleMessage);
    return () => {
      window.removeEventListener('message', handleMessage);
    };
  }, []);

  return (
    <div>
      <h1>웹뷰 페이지입니다</h1>
    </div>
  );
}

 


 

주의할 점은 없을까요?

브릿지를 사용할 때는 몇 가지 신경 써야 할 부분도 있습니다.

  • 앱과 웹 간에 주고받는 데이터 포맷은 JSON으로 명확히 통일해두는 게 좋습니다.
  • 보안상으로는 이벤트의 출처(origin) 를 검증하는 것도 고려해야 합니다.
  • 앞서 언급한 것처럼, 메시지 타이밍 이슈로 인해 앱의 데이터가 웹에서 누락되지 않도록 처리하는 것도 중요합니다.

 


 

마무리하며

이번 경험을 통해 앱과 웹 간의 통신 구조를 실제로 구현해보면서 브릿지에 대해 많이 배우게 됐습니다.
막연하게 어렵게 느껴졌던 부분이었지만, 한 번 구조를 이해하고 나니 생각보다 단순한 방식으로 잘 연결되더라고요.

혹시 저처럼 웹뷰 기반 앱에서 Native 기능과 통신해야 하는 상황이 있다면,
브릿지를 적극적으로 활용해보는 걸 추천드립니다.

 

이번 경험을 통해 앱과 웹 간의 통신 구조를 실제로 구현해보면서 브릿지에 대해 많이 배우게 됐습니다.
막연하게 어렵게 느껴졌던 부분이었지만, 한 번 구조를 이해하고 나니 생각보다 단순한 방식으로 잘 연결되더라고요.

혹시 저처럼 웹뷰 기반 앱에서 Native 기능과 통신해야 하는 상황이 있다면, 브릿지를 적극적으로 활용해보는 걸 추천드립니다.

 

 

반응형