[웹뷰 통신] React ↔︎ 네이티브 앱, React ↔︎ React 통신하기

April·2023년 5월 10일
2

React🚀

목록 보기
42/43

들어가기 전에,

이번 스프린트는 웹소설 기능 구현이었다.
epubjs 라이브러리를 사용해서 구현한 react 앱을 ios, android, web(Nextjs) 안에 띄워야 했고,
그 중 epubjs 라이브러리를 사용해서 react 앱을 구현하는 것이 내 목표였다.
(epubjs 라이브러리.. 제공하는 기능이 에러가 많아 힘든 라이브러리..😱😱)

해당 기능을 구현하는 과정에서 epubjs 라이브러리를 처음 다뤄보기도 했지만 웹뷰 통신도 처음 경험해보는 기능이었기에
2주 안에, 정확히는 공휴일 제외하고 영업일 7일 동안!!
QA버그 수정까지 마쳐야 하는 일정을 소화할 수 있을까 걱정도 많았지만 결국은 잘 끝냈다..💪💪👍😂

그 과정에서 처음 경험해본 웹뷰 통신을 간단히 기록해본다!



요구사항

ios, android, web에 웹뷰 형태로 띄워질 epub 뷰어 웹 어플리케이션을 구현한다.
네이티브(또는 Nextjs앱)와 통신하여 뷰어가 보여줄 epubUrl, 뷰어 스타일 등의 데이터를 주고받는다.



준비

💡 핵심은 window 객체를 이용하는 것!

  • 통신을 할 때 window 객체를 이용하게 되는데 미리 타입을 지정해두지 않으면 에러 발생
  • 구현하려는 함수 등을 window에 추가하기
// global.d.ts 예시
declare global {
  interface Window {
    webkit: {
      messageHandlers: {
        spWebNovel: {
          postMessage: (parameter: string) => void;
        };
      };
    };
    // 안드와 통신할 때 주고 받을 객체를 나눴다
    androidWebApi: {
      initContent: (parameter: InitContent) => void;
    androidWebViewApi: {
      spWebNovel: (parameter: string) => void;
    };

    initContent: (parameter: InitContent) => void;
  }
}

export {};


React ↔︎ 네이티브 앱 통신

보내기

// react가 ios에게 보내기
// 찾아보니  window.webkit.messageHandlers 안에 등록해야 한다고 한다
 window.webkit.messageHandlers.spWebNovel.postMessage(
      // ... 전달할 데이터
 );
 

// react가 안드로이드에게 보내기
// 안드에서 정의한 spWebNovel를 react가 호출해서 사용하는 방식
// 안드와 androidWebViewApi 안에 추가하기도 협의함
window.androidWebViewApi.spWebNovel(
	// ... 전달할 데이터
);

받기

  • react에서 ios 또는 안드가 사용할 함수를 정의해서 ios 또는 안드가 호출해서 사용하는 방식
// ios가 react의 함수 사용
 window.initContent(parameter) {
   // ... 로직
 };


// 안드가 react의 함수 사용
// 안드와 androidWebApi 안에 정의하기로 협의함
 window.androidWebApi.initContent(parameter) {
   // ... 로직
 };

React ↔︎ React(Nextjs) 통신

Window: postMessage() method - Web APIs | MDN

보내기

// 웹뷰를 품고 있는 상위에게 메세지 보내기
// iframe 입장에서 상위의 window에 메세지를 보내는 것이므로 parent애 접근!
 window.parent.postMessage(
   JSON.stringify({
     isReady: true,
   }),
   '*',
 );

받기

에러나지 않게 Window에 선언해주기

declare global {
  interface Window {
    initContent: (parameter: InitContent) => void;
    // ... 생략
  }
}

구현 코드 예시

const iframeRef = useRef<HTMLIFrameElement | null>(null);

useEffect(() => {
  iframeRef.current = document.getElementById('iframe') as HTMLIFrameElement;
}, []);

const handleButton = () => {
  // ... 생략
  
  // epub 뷰어에서 제공하는 함수 사용하기
  iframeRef.current?.contentWindow?.postMessage(
    {
      type: 'initContent', 
        parameter: {
             // ... 생략
        },
     },'*',
  );
}


추가: iOS에서 인스타그램 인앱, 크롬 브라우저에서 오류 발생!!

해당 기능이 구현되고 정식 배포 후..
iOS에서 인스타 인앱 브라우저와 크롬 브라우저에서 렌더링되지 않는 현상이 발생한다는 제보를 받게 되었다.😱


이슈

iOS 크롬 모바일, 인앱 브라우저에서 작동하지 않는 이슈 발생

원인 파악

iOS 크롬 모바일, 인앱 브라우저 환경에서

if (window.webkit?.messageHandlers) 

이 조건문이 통과되어

window.webkit.messageHandlers.spWebNovel.postMessage

이 로직이 실행되고 있었음.

해당 조건문은 iOS 네이티브 앱을 위한 조건문이었는데 iOS 브라우저 환경에서 통과되면서
정의되지 않은 객체 내부에 있는 메소드를 실행하게 되면서 undefined is not object 에러가 발생

해결 방법

이슈가 발생했던 조건문을 수정해서 해결

if (window.webkit?.messageHandlers?.spWebNovel?.postMessage) 

원인 파악2

왜 크롬 모바일앱에서 웹뷰 코드가 실행되었을까..??

[gpt의 답변]

크롬 모바일 앱에서 웹 뷰를 실행할 때, window.webkit.messageHandlers 객체를 통해 웹 콘텐츠와의 통신을 제공하기 위한 기능이 포함되어 있기 때문입니다.

window.webkit.messageHandlers 객체는 iOS에서 사용되는 WebView의 기능 중 하나로, iOS 앱과 웹 콘텐츠 간의 메시지 전달을 위한 인터페이스를 제공합니다. 이를 통해 iOS 앱에서 웹 페이지로 메시지를 보낼 수 있고, 웹 페이지에서 iOS 앱의 기능을 호출할 수 있습니다.




profile
🚀 내가 보려고 쓰는 기술블로그

0개의 댓글