Electron에 webview 도입하기

이승훈·2024년 11월 10일
0

시행착오

목록 보기
23/23

도입 취지

관리자 프로그램은 Electron으로 개발된 데스크톱 어플리케이션입니다.

그로인해 업데이트가 필요할 때, 병원 측에 별도로 연락하여 업데이트 버튼을 눌러야 하는 불편함이 있습니다.

특히, 현재와 같이 잦은 업데이트가 필요한 초기 단계에서는 병원과의 불필요한 소통이 발생할 수 있으며, 신속한 업데이트 적용이 어려운 문제가 있습니다.

(또한 버그 픽스가 바로바로 반영이 되지 않습니다.)

이러한 관리자 프로그램 업데이트 방식을 개선하기 위하여 로그인 후 실제 수검자 데이터를 조작하는 페이지는

electron에서 제공해주는 webview 태그를 사용하여 배포된 웹사이트를 보여주는 방식으로 개선합니다.

기존

로그인 페이지 : Electron의 Renderer 프로세스에서 보여줌

수검자 데이터 조작 페이지 : Electron의 Renderer 프로세스에서 보여줌

개선

로그인 페이지 : Electron의 Renderer 프로세스에서 보여줌

수검자 데이터 조작 페이지 : webview 태그를 사용하여 외부 웹사이트를 띄워줌, 외부 프로젝트로 분리된 수검자 데이터 조작 페이지는 vite를 사용하여 개발

webview(vite) ↔ Electron Rendere Process 통신 방법

Electron 에서 webview 로는 아래와같은 방식으로 메세지를 전송하는것이 가능합니다.

Electron → webview(vite 프로젝트) 로 메세지 보내기

import React, { useEffect, useRef } from "react";

const FullScreenWebview = () => {
  const webviewRef = useRef(null); // WebView 참조

  const sendMessageToWebview = () => {
    webviewRef.current.contentWindow.postMessage( <- 이거로 메세지 보냄
      "여기는 일렉트론 메시지를 보낸다",
      "*"
    );
  };

  return (
    <div
      style={{
        backgroundColor: "#edeff2",
        width: "100dvw",
        height: "100dvh",
      }}
    >
      <div
        style={{ width: 40, height: 40, backgroundColor: "red" }}
        onClick={() => {
          sendMessageToWebview();
        }}
      >
        버튼
      </div>
      <div style={{ height: "100%", width: "100%" }}>
        <webview
          ref={webviewRef}
          src={"http://localhost:5173/"} // Vite 서버 URL
          style={{ width: "100%", height: "100%" }}
          allowFullScreen
        />
      </div>
    </div>
  );
};

export default FullScreenWebview;

webview 내부(vite 프로젝트)에서 전달받은 메세지 읽고 처리하기

export default function InReactComponent() {

  window.addEventListener("message", (event) => {
    console.log("여기는 Vite 메세지를 받았다. -> 받은 메세지 :", event.data);
  });

  return (
  <div>SomethingComponentContetns</div>
  );
}

Electron에서 webview(vite 프로젝트)의 메세지 수신하여 처리하기

그러나 webview로 띄워지는 외부 프로젝트(현재 vite로 개발된 웹페이지)는 Electron으로 메세지를 전송할 수 없습니다.

그러나 Electron에서 webview로 보여지는 페이지의 console 기록은 읽는것이 가능합니다.

import React, { useEffect, useRef } from "react";

const FullScreenWebview = () => {
  const webviewRef = useRef(null); // WebView 참조

  useEffect(() => {
    const webviewElement = webviewRef.current;

    if (webviewElement) {
      const handleWebviewConsole = () => {
       // 이곳의 eventListener에서 웹뷰의 콘솔로그 기록을 읽는것이 가능
        webviewElement.addEventListener(    
          "console-message", 
          (e: { message: string }) => {
            console.log("Guest page logged a message:", e.message);
          }
        );
        webviewElement.openDevTools();
      };

      webviewElement.addEventListener("dom-ready", handleWebviewConsole);

      return () => {
        if (webviewElement) {
          webviewElement.removeEventListener("dom-ready", handleWebviewConsole);
        }
      };
    }
  }, []);

  const sendMessageToWebview = () => {
    webviewRef.current.contentWindow.postMessage( <- 이거로 메세지 보냄
      "여기는 일렉트론 메시지를 보낸다",
      "*"
    );
  };

  return (
    <div
      style={{
        backgroundColor: "#edeff2",
        width: "100dvw",
        height: "100dvh",
      }}
    >
      <div
        style={{ width: 40, height: 40, backgroundColor: "red" }}
        onClick={() => {
          sendMessageToWebview();
        }}
      >
        버튼
      </div>
      <div style={{ height: "100%", width: "100%" }}>
        <webview
          ref={webviewRef}
          src={"http://localhost:5173/"} // Vite 서버 URL
          style={{ width: "100%", height: "100%" }}
          allowFullScreen
        />
      </div>
    </div>
  );
};

export default FullScreenWebview;

따라서 webviewElectron 으로 메세지를 전송할 상황의 경우에는 console을 사용하여 메세지를 전달하는 방식으로 통신 방법을 설정하였습니다.

허나 console.log의 경우 노출되어있기 떄문에 별도의 데이터를 출력하는 경우는 없어야하며

reducer와 같이 action 상태를 전달하는 방식으로 통신이 이루어 집니다.

또한 보안을 강화하기 위해 console.debug를 사용하여 메세지를 전달합니다.

(console.debug를 사용하면 개발환경에서만 개발자도구에서 출력이 가능합니다)

아래는 console.debug를 통해 메세지를 전달하는 함수 코드의 예시입니다.

  const sendMessageToElectron = () => {
    // Electron으로 메시지 보내기
    const sendData = {
      type: "sendFromWebAdmin",
      action: "logout",
      executeFunction: `
        console.log('executeFunction')
      `,
    };
    console.debug(JSON.stringify(sendData));
  };

webview(vite) → Electron Rendere Process 통신 프로토콜

webviewElectron 으로 메세지를 전달할시에는 아래와 같은 객체형태로 데이터를 console.debug를 통해 데이터를 전달해야하며 각 action에 따른 Electron에서의 처리를 정의합니다.

{
	type:'sendFromWebAdmin',
	action : "logout" | "executeFunction" | "newWindowOpen" | "messageRecieveReady",
	executeFunction? : 'console.log('이 string이 Electron에서 함수로서 실행됩니다.')',
	newWindowUrl? :string;
}

1. action : logout

webview 내부의 웹페이지도 로그아웃되며 실제 Electron 어플리케이션에서도 로그아웃이 실행됩니다.

Electron에 저장된 토큰또한 다 지워집니다.

{
	type:'sendFromWebAdmin',
	action : "logout",
}

2. action : executeFunction

executeFunction 필드를 통해 전달받은 javascript 코드들이 Electron에서 실제로 실행됩니다.

executeFunction필드에는 import 같이 외부 모듈을 가져오는 것을 불가능하며 alert나 console.log같이

javascript 고유의 기능들만이 실행 가능합니다.

{
	type:'sendFromWebAdmin',
	action : "logout",
	executeFunction : `
	  아래와 같은 형식의 실행될 Javascript code 들
		console.log('someThing');
		alert('someThjing2');
	`
}

3. action : newWindowOpen

새로운 창이 띄워집니다.

{
	type:'sendFromWebAdmin',
	action : "newWindowOpen",
	newWindowUrl: '새창으로 열고자 하는 url(ex. 공지버튼 눌러서 공지창 열기)'
}

4. action : messageRecieveReady

webveiw(vite 프로젝트) 에서 돔트리가 완성된 후 메세지를 수신할 준비가 되었음을 알려줍니다.

Electron에서 해당 메세지를 수신하면 webview로 accessToken을 전달합니다.

{
	type:'sendFromWebAdmin',
	action : "messageRecieveReady",
}

어드민 로그인 프로세스

1. Electron 앱 실행

2. Electron 앱 로그인

  • 아이디, 패스워드, 병원 코드를 입력하여 서버에 전달 후 access token을 요청합니다.

3. access token 수령 및 저장

  • 요청한 access token을 Electron 앱으로 받아온 후 저장합니다.

4. webview 로드

  • 실제 수검자 데이터를 처리하는 어드민 웹페이지 url로 요청을 보낸 후 webview로 로드합니다.

5. dom-ready 상태 전달

  • webview 내부의 dom 트리가 완성된 후 Electron으로 부터 데이터(access token)을 받을 준비가 완료된 상태알림을 Electron으로 전달합니다.

6. webiew에서 전달하는 메세지 별 핸들링 설정을 Electron에 세팅

  • webview에서 logout, newWindowOpen 등의 메시지를 보내면 Electron에서 처리할 수 있도록 설정합니다.

7. messageRecieveReady 상태 전달(webview→Electron)

  • webveiw에서 이제 Electron으로부터 메세지를 받을 수 있는 상태가 되었음을 전달합니다.

8. access token 전달(Electron → webview)

  • Electron에 저장된 access token을 webview 내부 페이지로 전달합니다.

위 프로세스들이 완료되면 webview 내부에서는 access token을 가지고 수검자 정보를 처리할 수 있습니다.

(검수, 전송, 삭제 등의 기능)

profile
Beyond the wall

0개의 댓글