[Electron] 튜토리얼 Part 4: 기능 확장

렌더러 프로세스의 웹 기술 활용

렌더러 프로세스는 HTML, CSS, JavaScript를 기반으로 동작하므로, 웹 개발 기술을 그대로 활용 가능합니다.

  • UI 개선: 반응형 레이아웃, 애니메이션, SVG 그래픽 등을 추가해 사용자 경험을 향상시킵니다.
  • 기능 확장: 할 일 관리, 실시간 채팅, 차트 시각화 같은 기능을 구현할 수 있습니다.

운영체제 및 Node.js와의 통합

메인 프로세스를 통해 운영체제와 Node.js 기능을 활용 가능합니다. 이를 통해 네이티브 기능을 구현할 수 있습니다.

  • 네이티브 알림: 사용자에게 데스크탑 알림을 표시합니다.
  • 파일 시스템 접근: 파일 읽기/쓰기를 통해 데이터를 저장하거나 불러옵니다.
  • 시스템 통합: 단축키, 트레이, 메뉴 등 OS와의 상호작용을 지원합니다.

네이티브 알림과 파일 저장 기능 확장 예제

// main.js
const { app, BrowserWindow, ipcMain, Notification } = require('electron');
const fs = require('fs').promises; // 비동기 파일 쓰기 처리
const path = require('path');

let mainWindow;

async function createWindow() {
  mainWindow = new BrowserWindow({
    width: 1000,
    height: 700,
    title: 'Electron 기능 확장',
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
      contextIsolation: true,
      nodeIntegration: false
    }
  });

  await mainWindow.loadFile('index.html');

  // IPC 핸들러: 알림 표시
  ipcMain.handle('show-notification', (event, { title, body }) => {
    new Notification({ title, body }).show();
  });

  // IPC 핸들러: 파일 저장
  ipcMain.handle('save-file', async (event, content) => {
    // 사용자의 문서 폴더에 저장
    const filePath = path.join(app.getPath('documents'), 'electron-note.txt');
    try {
      await fs.writeFile(filePath, content, 'utf8');
      return `파일이 ${filePath}에 저장되었습니다.`;
    } catch (error) {
      return `파일 저장 실패: ${error.message}`;
    }
  });
}

app.whenReady().then(() => {
  createWindow();

  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) createWindow();
  });
});

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') app.quit();
});
// preload.js
const { contextBridge, ipcRenderer } = require('electron');
// contextBridge를 통해 main.js에서 통신할 API를 노출시킵니다.
contextBridge.exposeInMainWorld('electronAPI', {
  showNotification: (options) => ipcRenderer.invoke('show-notification', options),
  saveFile: (content) => ipcRenderer.invoke('save-file', content)
});
// index.html
<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
  <title>Electron 기능 확장</title>
</head>
<body>
  <h1>Electron 기능 확장 데모</h1>
  <textarea id="note" placeholder="여기에 메모를 입력하세요"></textarea>
  <button onclick="handleSubmit()">알림 표시 및 저장</button>
  <p id="result"></p>

  <script src="renderer.js"></script>
</body>
</html>
// renderer.js
(async () => {
  const noteEl = document.getElementById('note');
  const resultEl = document.getElementById('result');

  async function handleSubmit() {
    const content = noteEl.value.trim();
    if (!content) {
      resultEl.textContent = '내용을 입력하세요!';
      return;
    }

    // 네이티브 알림 표시
    await window.electronAPI.showNotification({
      title: '새 메모',
      body: content.slice(0, 50) + (content.length > 50 ? '...' : '')
    });

    // 파일 저장
    const saveResult = await window.electronAPI.saveFile(content);
    resultEl.textContent = saveResult;
  }
})();