[ElectronJs] UI Renderer와 Main의 Interface 통신

seohyun Kang·2022년 7월 14일

Electron

목록 보기
2/2

Introduction

Electron은 Main Process를 Nodejs 환경에서 수행하며, Electron Module, Nodejs 내장 기능 및 NPM으로 설치된 모든 패키지에 접근이 가능합니다.

반면에, 웹 페이지를 실행하는 Renderer Process는 보안상의 이유로 Nodejs를 실행하지 않습니다.

이 때문에, Electron에서 Main Process와 Renderer Process를 연결하려면 Preload Script를 사용해야합니다.


What is the Preload Script

Preload Script는 HTML Dom & Nodejs env 모두에서 액세스할 수 있는 Context에서 실행되며, 웹 페이지가 Renderer에 의해 로드되기 전에 주입됩니다.


How to use Preload Script

preload.js를 작성하여 Preload Script를 프로젝트에 적용하는 과정을 진행하겠습니다.

// Example
// preload.js

const { contextBridge, ipcRenderer } = require('electron');

const nameOfInterface = "bridge";

contextBridge.exposeInMainWorld(nameOfInterface, {
  // Set interface to use
  ipcRenderer: {
    sendMessage: (channel, args) => {
      ipcRenderer.send(channel, args);
    },
    on: (channel, func) => {
      const subscription = (_event, ...args) => func(...args);
      ipcRenderer.on(channel, subscription);

      return () => ipcRenderer.removeListener(channel, subscription);
    },
    once: (channel, func) => {
      ipcRenderer.once(channel, (_event, ...args) => func(...args));
    },
  },
});

사전 정의된 interface의 기능과 관련된 스크립트를 preload.js에 작성합니다.

해당 기능은 추후 Renderer에서 window.bridge.emit() || window.bridge.on()과 같은 방식으로 호출할 수 있습니다.

// main.js
const { app, BrowserWindow } = require('electron')
const path = require('path')

const createWindow = () => {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
    },
  })

  win.loadFile('index.html')
}

preload.js를 main.js에 통합합니다.

// preload.d.ts

declare global {
  interface Window {
    bridge: {
      ipcRenderer: {
        sendMessage(channel: string, args: unknown[]): void;
        on(
          channel: string,
          func: (...args: unknown[]) => void
        ): (() => void) | undefined;
        once(channel: string, func: (...args: unknown[]) => void): void;
      };
    };
  }
}

Renderer에 global object로 electron interface를 호출할 수 있도록 선언합니다.

// Renderer
// index.tsx

const interfaceCall = async () => {
	await window.bridge.ipcRenderer.sendMessage("test", ["arg"]);
}

Renderer측의 interface bridge 연결작업은 이렇게 끝입니다. 다음은 main.js를 추가 작업하겠습니다.

// main.js

const { app, BrowserWindow, ipcMain } = require('electron')
const path = require('path')

const createWindow = () => {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
    },
  })
	
  const ipcMethodName = "" // preload.js에 선언된 interface bridge method 명을 사용합니다.
  ipcMain.on(${ipcMethodName}, () => {
  	console.log("Running");
  })
  win.loadFile('index.html')
}

이렇게, Renderer와 Main Process간 Interface 통신 연결 튜토리얼을 정리하겠습니다.


References : Electron-Preload-Tutorial

0개의 댓글