autoUpdater모듈

Category
스터디노트 Electron
Status
Published
Tags
자동 업데이트
Electron
Desktop Application
Description
Published
Slug
autoUpdater는 Electron 애플리케이션에서 자동 업데이트 기능을 구현하는 데 사용되는 모듈
이 모듈을 사용하면 애플리케이션이 스스로 업데이트를 다운로드하고 설치할 수 있게 됨

기본 개념

  • autoUpdater모듈은 EventEmitter를 상속받아 이벤트 기반으로 동작함
  • 지원 플랫폼: 현재 macOS와 Windows에서만 자동 업데이트를 지원.
  • Linux는 기본적으로 지원하지 않으며, 대신 배포판의 패키지 관리자를 사용하는 것이 권장됨
 

플랫폼별 특이 사항

macOS

  • 기반: autoUpdater 모듈은 Squirrel.Mac에 기반하여 동작. 별도의 설정 없이 기본적으로 동작하지만, 서버 쪽에서 특정 요구 사항을 충족해야 할 수 있음.
  • 앱 서명: macOS에서는 자동 업데이트를 위해 애플리케이션이 반드시 서명되어 있어야 함.
  • App Transport Security (ATS): 업데이트 과정에서 이루어지는 모든 요청은 ATS의 적용을 받음
    • 만약 ATS를 비활성화해야 한다면, 앱의 plist 파일에 NSAllowsArbitraryLoads 키를 추가해야 함.

Windows

  • 기반: Windows에서는 Squirrel.Windows에 기반하여 동작
  • 설치 필수: autoUpdater를 사용하기 전에 애플리케이션이 사용자 시스템에 설치되어 있어야 합니다. 이를 위해 electron-winstaller, Electron Forge, grunt-electron-installer 등의 패키지를 사용해 설치 프로그램을 생성하는 것이 권장됨
  • 첫 실행 시 업데이트 비활성화: electron-winstallerElectron Forge를 사용하는 경우, 애플리케이션이 처음 실행될 때 업데이트를 시도하지 않도록 설정해야 함
  • electron-squirrel-startup: 데스크탑에 애플리케이션의 바로가기를 자동으로 생성하는 패키지로, 업데이트와 설치 과정에서 유용
  • 앱 사용자 모델 ID: Windows에서는 Squirrel이 생성한 바로가기에 Application User Model ID가 부여됨. 이 ID는 app.setAppUserModelId API에서 동일하게 설정해야 Windows가 애플리케이션을 올바르게 인식하고 작업 표시줄에 고정할 수 있음.
 

이벤트

autoUpdater 객체는 여러 이벤트를 발생시킴
  • error: 업데이트 도중 오류가 발생했을 때 발생합니다.
  • checking-for-update: 업데이트를 확인하는 작업이 시작되었을 때 발생
  • update-available: 새로운 업데이트가 있을 때 발생하며, 이때 업데이트는 자동으로 다운로드
  • update-not-available: 업데이트가 없을 때 발생
  • update-downloaded: 업데이트가 다운로드된 후 발생. 이 이벤트는 다운로드된 업데이트를 설치하기 전에 필요한 작업을 수행할 수 있는 기회를 제공.
  • before-quit-for-update: quitAndInstall()이 호출된 후, 애플리케이션이 종료되기 전에 발생. 이 이벤트를 통해 애플리케이션 창이 닫히기 전에 작업을 수행할 수 있음.

메서드

autoUpdater 객체는 여러 가지 메서드를 제공:
  • setFeedURL(options): 업데이트를 다운로드할 URL을 설정하고 자동 업데이트를 초기화.
    • options 객체는 url, headers(선택적, macOS 전용), serverType(선택적, macOS 전용) 등의 속성을 포함.
  • getFeedURL(): 현재 설정된 업데이트 피드 URL을 반환.
  • checkForUpdates(): 서버에 업데이트가 있는지 확인. setFeedURL을 먼저 호출해야 하며, 업데이트가 있으면 자동으로 다운로드됨.
  • quitAndInstall(): 업데이트가 다운로드된 후 애플리케이션을 재시작하고 업데이트를 설치. 이 메서드는 update-downloaded 이벤트가 발생한 후에만 호출해야 함.

사용 예시

  1. 피드 URL 설정:
    1. const { autoUpdater } = require('electron'); autoUpdater.setFeedURL({ url: 'https://your-update-server.com/updates/latest', });
  1. 업데이트 확인 및 설치:
    1. autoUpdater.checkForUpdates(); autoUpdater.on('update-downloaded', () => { autoUpdater.quitAndInstall(); });
 
  • autoUpdater 모듈은 Electron 애플리케이션이 자동으로 업데이트할 수 있도록 도와주는 모듈
  • Windows와 macOS에서만 지원하며, 각 플랫폼마다 특별한 설정이나 요구 사항이 있습니다.
  • 업데이트를 다운로드하고 설치하는 과정은 이벤트 기반으로 진행되며, 개발자는 이러한 이벤트를 통해 사용자 경험을 맞춤 설정할 수 있습니다.
  • Linux는 자동 업데이트를 기본적으로 지원하지 않으므로, 각 배포판의 패키지 관리자를 사용하는 것이 좋습니다.
 
 
  • 이벤트
    • 'error': 업데이트 중 오류 발생 시
    • 'checking-for-update': 업데이트 확인 시작 시
    • 'update-available': 사용 가능한 업데이트가 있을 때
    • 'update-not-available': 사용 가능한 업데이트가 없을 때
    • 'update-downloaded': 업데이트 다운로드 완료 시
    • 'before-quit-for-update': 사용자가 quitAndInstall() 호출 시
  • 주요 메서드
    • setFeedURL(options): 업데이트 피드 URL 설정
    • getFeedURL(): 현재 업데이트 피드 URL 반환
    • checkForUpdates(): 서버에 업데이트 확인 요청
    • quitAndInstall(): 앱 재시작 및 다운로드된 업데이트 설치
  • 주의사항:
    • checkForUpdates()를 두 번 호출하면 업데이트를 두 번 다운로드합니다.
    • quitAndInstall()은 update-downloaded 이벤트 발생 후에만 호출해야 합니다.
    • 성공적으로 다운로드된 업데이트는 다음 앱 실행 시 자동으로 적용됩니다.
 
 



자동 업데이트가 있는 경우 사용자에게 선택할 수 있는 옵션을 제공하고,
사용자가 수락하면 업데이트를 진행하도록 애플리케이션을 설정하려면, autoUpdater와 IPC(Inter-Process Communication)를 활용할 수 있습니다.
 
이를 통해 업데이트가 감지되면 사용자에게 알림을 표시하고, 사용자가 수락하면 업데이트를 진행할 수 있습니다.
아래는 기존 코드에 이 기능을 추가하는 방법

1. main.js 업데이트

먼저, autoUpdater를 설정하고, 업데이트가 있을 때 사용자에게 알림을 보내는 기능을 추가
// main.js require("update-electron-app")(); const { app, BrowserWindow, ipcMain, dialog } = require("electron"); const { autoUpdater } = require("electron-updater"); // electron-updater 모듈을 불러옴 const path = require("node:path"); function createWindow() { let win = new BrowserWindow({ width: 800, height: 600, webPreferences: { preload: path.join(__dirname, "preload.js"), }, }); win.loadFile("index.html"); // IPC 핸들러 설정: 업데이트 수락 시 호출 ipcMain.handle("install-update", () => { autoUpdater.quitAndInstall(); // 업데이트를 설치하고 앱을 종료 후 재시작 }); } app.whenReady().then(() => { ipcMain.handle("ping", () => "pong"); createWindow(); // 앱이 준비되면 업데이트 확인을 시작 autoUpdater.checkForUpdates(); // 업데이트 확인 시작 autoUpdater.on('checking-for-update', () => { console.log('Checking for updates...'); }); // 업데이트 가능 시 이벤트 처리 autoUpdater.on('update-available', (info) => { console.log('Update available.'); BrowserWindow.getAllWindows()[0].webContents.send('update-available', info); // 업데이트 가능함을 렌더러 프로세스에 알림 }); // 업데이트가 없을 시 이벤트 처리 autoUpdater.on('update-not-available', () => { console.log('Update not available.'); }); // 업데이트 다운로드 완료 시 이벤트 처리 autoUpdater.on('update-downloaded', (info) => { BrowserWindow.getAllWindows()[0].webContents.send('update-downloaded', info); // 업데이트 다운로드 완료를 렌더러 프로세스에 알림 }); app.on("activate", () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } }); }); app.on("window-all-closed", () => { if (process.platform !== "darwin") app.quit(); });

2. preload.js 업데이트

메인 프로세스와 렌더러 프로세스 간의 통신을 위해 필요한 IPC 메시지를 설정
// preload.js const { contextBridge, ipcRenderer } = require("electron"); contextBridge.exposeInMainWorld("versions", { node: () => process.versions.node, chrome: () => process.versions.chrome, electron: () => process.versions.electron, ping: () => ipcRenderer.invoke("ping"), installUpdate: () => ipcRenderer.invoke("install-update"), // 업데이트 설치 요청 }); contextBridge.exposeInMainWorld("autoUpdater", { onUpdateAvailable: (callback) => ipcRenderer.on("update-available", callback), // 업데이트 가능 이벤트 수신 onUpdateDownloaded: (callback) => ipcRenderer.on("update-downloaded", callback), // 업데이트 다운로드 완료 이벤트 수신 });

3. renderer.js 업데이트

업데이트가 가능할 때와 다운로드가 완료되었을 때 사용자에게 알림을 표시하는 코드를 작성
// renderer.js const information = document.getElementById("info"); information.innerText = `This app is using Chrome (v${versions.chrome()}), Node.js (v${versions.node()}), and Electron (v${versions.electron()})`; const func = async () => { const response = await window.versions.ping(); console.log(response); }; func(); // 업데이트가 가능할 때 이벤트 처리 window.autoUpdater.onUpdateAvailable((event, info) => { const userResponse = confirm('A new update is available. Do you want to update now?'); if (userResponse) { window.versions.installUpdate(); // 업데이트 설치 요청 } }); // 업데이트가 다운로드되었을 때 이벤트 처리 window.autoUpdater.onUpdateDownloaded((event, info) => { alert('Update downloaded and will be installed on restart.'); });

4. index.html

이전과 동일하게 유지할 수 있음