electron 기초

강정우·2025년 9월 11일
0

electron

목록 보기
1/1

간단한 앱 만들기

마치 web-app 처럼 electron 을 사용해서 mini-pc 에 application 을 만들어볼 예정이다.

1. electron

electron 의 구성은 일단
index.html => splash 화면
package.json => 명세서 역할
main.js => landing-page 역할

여기에 추가적으로 본인이 원하는 파일을 목적에 만들면 된다.

preload.js => 해당 app 이 뜨기 전에 값을 가져오는 역할
updater.js => s3, object box 와 같이 자동으로 update 될 수 있도록 람다를 역할을 하는 곳.

그럼 이제 하나하나 천천히 살펴보자.

1. index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Simple Electron App</title>
    <style>
        body, html {
            margin: 0;
            padding: 0;
            height: 100%;
            overflow: hidden;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .background-image {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-image: url('splash.jpg'); /* Replace with your image URL */
            background-size: cover;
            background-position: center;
            z-index: -1;
        }

        .text-container {
            position: absolute;
            top: 80%;
            color: white;
            font-family: Arial, sans-serif;
            font-size: 2rem;
            text-align: center;
            background: rgba(0, 0, 0, 0.5); /* Optional: Adds a translucent background */
            padding: 20px;
            border-radius: 10px;
        }
    </style>
</head>
<body>
<script type="text/javascript">
  var Request = function () {
    this.getParameter = function (name) {
      var rtnval = '';
      var nowAddress = unescape(location.href);
      var parameters = (nowAddress.slice(nowAddress.indexOf('?') + 1,
        nowAddress.length)).split('&');
      for (var i = 0; i < parameters.length; i++) {
        var varName = parameters[i].split('=')[0];
        if (varName.toUpperCase() == name.toUpperCase()) {
          rtnval = parameters[i].split('=')[1];
          break;
        }
      }
      return rtnval;
    }
  }
  var request = new Request();
</script>

<div class="background-image"></div>
<div class="text-container" id="did">device ID</div>

<script type="text/javascript">
  var deviceParam = request.getParameter('deviceID');
  var versionParam = request.getParameter('ver');
  document.getElementById('did').innerHTML = deviceParam + '<br>Ver.' + versionParam;
</script>

<script>
  var timer = setTimeout(function () {
    var webclient_url = 'http://localhost:3000';
    window.location.href = `${webclient_url}?deviceID=${deviceParam}`;
  }, 3000);
</script>

<script>
  document.addEventListener('keydown', (event) => {
    if (event.key === 'Enter') {
      console.log('✔ OK 버튼이 브라우저에서 감지됨!');
    }
  });
</script>

</body>
</html>

뭐 이런식으로 간단하게 작성해도 된다.

하지만 나는 electron work flow 가 package.json => main.js 로 실행되어 createWindow 에서 바로 react 서버를 요청했고 이를 가져와 표출하기로 했다.
참고로 react 에서 type 만 잘 잡아두고, electron 에서 ipc 를 사용하여 터널만 잘 뚫어 놓으면 OS 단의 정보를 react 에서도 받아볼 수 있다.

2. package.json

{
  "author": "kjw",
  "name": "레포 이름",
  "version": "1.0.0",
  "description": "레포 설명",
  "main": "main.js",
  "scripts": {
    "start": "electron .",
    "dev": "electron . --enable-logging",
    "build": "electron-builder",
    "dist": "electron-builder --publish=never",
    "build:linux64": "electron-builder --linux --x64",
    "build:win64": "electron-builder --win --x64",
    "postinstall": "electron-builder install-app-deps"
    "build-publish": "electron-builder --publish=always",
    "deploy": "node deploy-to-gcs.js"
  },
  "author": "kjw",
  "license": "ISC",
  "devDependencies": {
    "electron-builder": "^26.0.12",
    "electron-log": "^5.4.2",
    "electron-updater": "^6.6.2"
  }
  "build": {
    "appId": "앱 아이디",
    "productName": "앱 이름",
    "asar": true,
    "asarUnpack": [
      "node_modules/node-hid/**"
    ],
    "protocols": {
      "name": "SmartSilverClient",
      "schemes": [
        "SmartSilverClient"
      ]
    },
    "files": [
      "**/*"
    ],
    "win": {
      "target": [
        "zip",
        "nsis"
      ],
      "icon": "./resources/installer/Icon.ico"
    },
    "linux": {
      "target": [
        "AppImage",
        "zip",
        "tar.gz"
      ],
      "icon": "./resources/linuxicon"
    },
    "nsis": {
      "oneClick": false,
      "allowToChangeInstallationDirectory": true
    },
    "directories": {
      "buildResources": "./resources/installer/",
      "output": "./dist/",
      "app": "."
    }
  },
  "type": "commonjs",
  "dependencies": {
    "@electron/rebuild": "^4.0.1",
    "electron": "^37.2.5",
    "node-hid": "^3.2.0"
  },
  
}

electron 에서 package.json 의 build 옵션은 굉장히 중요한 역할을 한다.
AppImage 를 생성하는 옵션들을 여기서 설정하기 때문이다.

기본 설정

productName: 최종 사용자에게 표시될 애플리케이션 이름이다. 여기서 설정한 이름 + 버전.AppImage 로 빌드됨.
appId: 애플리케이션의 고유 식별자로, 주로 도메인 역순 형식을 사용한다.
asar: 애플리케이션 소스 코드를 asar 아카이브로 패키징한다. 성능 향상 + 코드 보호

build - 파일 설정

files: 최종 빌드에 포함될 파일들을 지정.

"files": [
  "index.html",
  "main.js",
  "splash.jpg",
  "node_modules/node-hid/**/*"
  // 아니면 그냥 프로젝트 내 모든 파일 설정
  "**/*"
]

build - asarUnpack

asar 아카이브로 패키징하지 않을 파일들을 지정하는 필드

"asarUnpack": [
  "node_modules/node-hid/**"
],

참고로 node-hid 모듈은 네이티브 모듈이므로 asar에서 풀어야 정상 작동한다.

build - protocols

프로토콜 설정
protocols: 커스텀 URL 스킴을 정의합니다.

"protocols": {
  "name": "앱 이름",
    "schemes": [
      "앱 이름"
    ]
},

이를 통해 앱 이름:// 형식의 URL로 애플리케이션을 실행할 수 있다.

build - Windows

electron-builder 설정의 일부

"win": {
  "target": [
    "zip",
    "nsis"
  ],
    "icon": "./resources/installer/Icon.ico"
},

zip: 압축 파일 형태로 배포
nsis: Windows 설치 프로그램으로 배포
win.icon: Windows 애플리케이션 아이콘

window 필드

1. NSIS 는 사용자가 window 에서 설치할 때 필요한 건가?

NSIS (Nullsoft Scriptable Install System)는 Windows 운영체제에서 소프트웨어 설치 파일을 만들 때 사용하는 도구이다.
NSIS는 다양한 역할을 하는데, 1. Windows 설치 파일(exe) 생성 2. .nsi 확장자를 작성하여 설치 과정을 세밀하게 제어 가능 3. 다양한 기능제공 예를 들어 설치 경로 설정, 구성 요소 선택, 언인스톨러 생성, 프로그램 실행 여부 설정 등 그리고 무엇보다 무료 및 오픈 소스이다.
2. asar 아카이브란?
asar(Atom Shell Archive Format) 아카이브는 Electron 애플리케이션을 위해 특별히 설계된 간단한 확장 아카이브 포맷이다.
tar와 비슷한 방식으로 작동한다. 무슨 말이냐면 애플리케이션의 모든 소스 코드와 리소스 파일들을 압축 없이 하나의 파일로 묶어주는 역할을 한다.
파일 통합: 여러 파일을 하나로 묶어 관리가 용이
성능 최적화: asar 아카이브를 압축 해제 없이 임의로 접근하여 필요한 파일만 읽어들일 수 있음
경로 문제 해결: Windows에서 발생할 수 있는 긴 경로 이름 관련 문제를 완화
소스 코드 보호: 애플리케이션 배포 시 소스 코드를 직접 노출하지 않고 패키징할 수 있음
이러한 장점이 있어, win build 시 asar 아카이브로 패키징하도록 설정을 한다.

build - Linux

electron-builder 설정의 일부

"linux": {
  "target": [
    "AppImage",
    "zip",
    "tar.gz"
  ],
  "icon": "./resources/linuxicon",
  "category": "Utility"
},

AppImage: 설치 없이 실행 가능한 독립형 애플리케이션 파일
zip 및 tar.gz: 압축 파일 형태
linux.icon: 애플리케이션 아이콘

"build:linux64": "electron-builder --linux --x64",
target 속성을 통해 Linux에서 어떤 배포 형식(어떤 형태의 패키지)으로 배포할지 지정한다.
AppImage: 설치 없이 실행 가능한 독립형 애플리케이션 파일
deb: Debian 기반 리눅스(Ubuntu 등)에서 사용하는 패키지 형식
아키텍처 지정: arch 속성은 지원할 CPU 아키텍처를 지정한다.
x64: 64비트 인텔/AMD 프로세서
arm64: 64비트 ARM 프로세서(라즈베리파이 등)
이렇게 설정하면 두 가지 배포 형식(AppImage, deb)과 두 가지 아키텍처(x64, arm64)에 대해 총 4개의 다른 빌드 파일이 생성된다.

  • category 필드는 Linux 데스크톱 환경에서 애플리케이션의 분류를 지정한다.
    메뉴 분류: Linux 데스크톱 환경(GNOME, KDE 등)의 애플리케이션 메뉴에서 어느 카테고리에 표시될지 결정합니다. "Utility"로 설정되어 있으므로 유틸리티 도구 섹션에 표시된다.
    데스크톱 파일 정보: Linux에서는 .desktop 파일에 이 카테고리 정보가 포함되어, 시스템이 애플리케이션을 적절히 분류하고 표시할 수 있게 한다.
    참고로 다른 카테고리로는 "Development", "Graphics", "Network", "Office", "System" 등이 있다.

build - NSIS 설치 프로그램 설정

nsis.oneClick: false - 원클릭 설치 대신 사용자 정의 설치 옵션을 제공하는 옵션
nsis.allowToChangeInstallationDirectory: true - 사용자가 설치 디렉토리를 변경할 수 있도록 도와주는 옵션

build - directory

"directories": {
  "buildResources": "./resources/installer/",
    "output": "./dist/",
      "app": "."
}

buildResources: 빌드에 필요한 리소스 파일 위치
output: 빌드된 파일이 저장될 폴더 명
app: 애플리케이션 소스 코드 위치 참고로 .는 현재 디렉토리를 사용한다는 의미임.

keywords

keywords 필드는 패키지를 설명하는 키워드 모음이다.
1. 검색 최적화: npm에 패키지를 등록했을 때, 다른 개발자들이 관련 키워드로 검색했을 때 발견될 수 있게 도와준다.
2. 패키지 설명: 패키지의 용도나 특성을 간략하게 표현한다. 예를 들어 "electron", "smartsilver", "webclient"라는 키워드를 통해 이 애플리케이션이 Electron 기반의 SmartSilver 웹 클라이언트임을 나타낸다.
3. 분류: npm 생태계에서 비슷한 용도의 패키지들과 함께 분류될 수 있도록 한다.

자동 실행 스크립트

이제 electron 의 기본 골조와 package.json 을 알아봤으면 linux 환경에서 자동으로 실행할 수 있도록 스크립트를 아래와 같이 작성해주면 된다.

/homr/user/.config/autostart/xxx.desktop 에 다음과 같이 작성해주고

[Desktop Entry]
Type=Application
Exec=/home/user/launch-settop.sh
Hidden=false
NoDisplay=false
X-GNOME-Autostart-enabled=true
Name[en_US]=settop
Name=settop
Comment[en_US]=
Comment=

해당 스크립트를 작성해준다.

#!/bin/bash
LATEST_APP=$(ls -t /home/user/본인앱이름-*.AppImage | head -1)
exec "$LATEST_APP"

그리고 아래 권한을 부여하면

chmod +x /home/user/launch-settop.sh

이제 pc 가 켜지면 자동으로 해당 app 이 실행된다.

npm run dev

우리가 테스트를 할 때 development 환경에서 실행할 때가 있다.
이를 위해 package.json 을 이렇게 바꿔주고,

"scripts": {
  "dev": "cross-env NODE_ENV=development electron . --enable-logging"
}

Electron 자체의 Linux SUID sandbox 문제를 해소하기 위해 다음과 같이 명령어를 입력해주면 된다.

sudo chown root:root /home/ubuntu/dev/node_modules/electron/dist/chrome-sandbox
sudo chmod 4755 /home/ubuntu/dev/node_modules/electron/dist/chrome-sandbox

이를 실행하는 이유는 Linux에서 Electron을 설치하면 sandbox 기능 때문에 일반 사용자로 바로 실행하면 오류가 발생할 수 있기 때문이다.

profile
智(지)! 德(덕)! 體(체)!

0개의 댓글