Electron: 간편한 크로스 플랫폼 데스크탑 앱

게시 됨: 2022-03-11

올해 초 Github은 유명한 오픈 소스 편집기 Atom의 핵심인 Atom-Shell을 출시하고 특별한 행사를 위해 이름을 Electron 으로 변경했습니다.

Electron은 Node.js 기반 데스크톱 애플리케이션 카테고리의 다른 경쟁자들과 달리 Node.js(최신 릴리스까지 io.js)의 성능과 Chromium Engine을 결합하여 이미 잘 정립된 이 시장에 고유한 방식을 도입했습니다. 우리는 서버와 클라이언트 측 JavaScript의 최고를 제공합니다.

끊임없이 성장하는 NPM 모듈의 저장소뿐만 아니라 전체 Bower 레지스트리로 구동되는 성능이 뛰어난 데이터 기반 크로스 플랫폼 데스크톱 애플리케이션을 구축하여 모든 클라이언트 측 요구를 충족할 수 있는 세상을 상상해 보십시오.

전자를 입력합니다.

Electron으로 크로스 플랫폼 데스크탑 앱 구축하기

Electron으로 크로스 플랫폼 데스크탑 앱 구축하기
트위터

이 자습서에서는 MongoDB 개발자에게 친숙한 구문을 사용하는 경량 인메모리 데이터베이스인 Electron, Angular.js 및 Loki.js를 사용하여 간단한 암호 키체인 애플리케이션을 구축합니다.

이 응용 프로그램의 전체 소스 코드는 여기에서 사용할 수 있습니다.

이 자습서에서는 다음을 가정합니다.

  • 리더의 컴퓨터에는 Node.js와 Bower가 설치되어 있습니다.
  • 그들은 Node.js, Angular.js 및 MongoDB와 유사한 쿼리 구문에 익숙합니다.

상품 받기

먼저 앱을 로컬에서 테스트하려면 Electron 바이너리를 가져와야 합니다. 전역적으로 설치하여 CLI로 사용하거나 애플리케이션 경로에 로컬로 설치할 수 있습니다. 전 세계적으로 설치하는 것이 좋습니다. 그래야 우리가 개발하는 모든 앱에 대해 반복해서 설치할 필요가 없습니다.

Gulp를 사용하여 배포용 애플리케이션을 패키징하는 방법은 나중에 배울 것입니다. 이 프로세스에는 Electron 바이너리 복사가 포함되므로 애플리케이션 경로에 수동으로 설치하는 것은 거의 의미가 없습니다.

Electron CLI를 설치하기 위해 터미널에 다음 명령을 입력할 수 있습니다.

 $ npm install -g electron-prebuilt

설치를 테스트하려면 electron -h 를 입력하면 Electron CLI 버전이 표시됩니다.

이 글이 작성될 당시 Electron의 버전은 0.31.2 .

프로젝트 설정

다음과 같은 기본 폴더 구조를 가정해 보겠습니다.

 my-app |- cache/ |- dist/ |- src/ |-- app.js | gulpfile.js

... 여기서: - cache/ 는 앱을 빌드할 때 Electron 바이너리를 다운로드하는 데 사용됩니다. - dist/ 는 생성된 배포 파일을 포함합니다. - src/ 에는 소스 코드가 포함됩니다. - src/app.js 는 우리 애플리케이션의 진입점이 될 것입니다.

다음으로 터미널의 src/ 폴더로 이동하여 앱에 대한 package.jsonbower.json 파일을 생성합니다.

 $ npm init $ bower init

이 자습서의 뒷부분에서 필요한 패키지를 설치합니다.

전자 프로세스 이해

Electron은 두 가지 유형의 프로세스를 구분합니다.

  • Main Process : 애플리케이션의 진입점으로, 앱을 실행할 때마다 실행될 파일입니다. 일반적으로 이 파일은 앱의 다양한 창을 선언하며 선택적으로 Electron의 IPC 모듈을 사용하여 전역 이벤트 리스너를 정의하는 데 사용할 수 있습니다.
  • 렌더러 프로세스 : 애플리케이션에서 주어진 창에 대한 컨트롤러입니다. 각 창은 자체 렌더러 프로세스를 만듭니다.

코드 명확성을 위해 각 렌더러 프로세스에 대해 별도의 파일을 사용해야 합니다. 앱의 메인 프로세스를 정의하기 위해 src/app.js 를 열고 앱을 시작하기 위한 app 모듈과 앱의 다양한 창을 생성하기 위한 browser-window 모듈(둘 모두 Electron 코어의 일부)을 포함합니다. 다음과 같이:

 var app = require('app'), BrowserWindow = require('browser-window');

앱이 실제로 시작되면 바인딩할 수 있는 ready 이벤트가 발생합니다. 이 시점에서 앱의 기본 창을 인스턴스화할 수 있습니다.

 var mainWindow = null; app.on('ready', function() { mainWindow = new BrowserWindow({ width: 1024, height: 768 }); mainWindow.loadUrl('file://' + __dirname + '/windows/main/main.html'); mainWindow.openDevTools(); });

키 포인트:

  • BrowserWindow 개체의 새 인스턴스를 만들어 새 창을 만듭니다.
  • 객체를 단일 인수로 사용하여 창의 기본 너비높이 를 비롯한 다양한 설정을 정의할 수 있습니다.
  • 창 인스턴스에는 현재 창에서 실제 HTML 파일의 내용을 로드할 수 있는 loadUrl() 메서드가 있습니다. HTML 파일은 로컬 또는 원격 일 수 있습니다.
  • 창 인스턴스에는 선택적 openDevTools() 메서드가 있어 디버깅 목적으로 현재 창에서 Chrome 개발자 도구의 인스턴스를 열 수 있습니다.

다음으로 코드를 약간 정리해야 합니다. src/ 폴더에 windows/ 폴더를 만들고 각 창에 대해 다음과 같이 하위 폴더를 만들 수 있습니다.

 my-app |- src/ |-- windows/ |--- main/ |---- main.controller.js |---- main.html |---- main.view.js

... 여기서 main.controller.js 는 애플리케이션의 "서버 측" 로직을 포함하고 main.view.js 는 애플리케이션의 "클라이언트 측" 로직을 포함합니다.

main.html 파일은 단순히 HTML5 웹페이지이므로 다음과 같이 간단히 시작할 수 있습니다.

 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Password Keychain</title> </head> <body> <h1>Password Keychain</h1> </body> </html>

이 시점에서 앱을 실행할 준비가 되어 있어야 합니다. 테스트하기 위해 터미널의 src 폴더 루트에 다음을 입력하기만 하면 됩니다.

 $ electron .

package.son 파일의 start 스크립트를 정의하여 이 프로세스를 자동화할 수 있습니다.

암호 키체인 데스크탑 앱 빌드

암호 키체인 응용 프로그램을 구축하려면 다음이 필요합니다. - 암호를 추가, 생성 및 저장하는 방법. - 암호를 복사하고 제거하는 편리한 방법입니다.

비밀번호 생성 및 저장

새 암호를 삽입하려면 간단한 형식으로 충분합니다. Electron의 여러 창 간의 통신을 보여주기 위해 "삽입" 형식을 표시할 두 번째 창을 애플리케이션에 추가하는 것으로 시작합니다. 이 창을 여러 번 열고 닫을 것이므로 필요할 때 간단히 호출할 수 있도록 메서드에 논리를 래핑해야 합니다.

 function createInsertWindow() { insertWindow = new BrowserWindow({ width: 640, height: 480, show: false }); insertWindow.loadUrl('file://' + __dirname + '/windows/insert/insert.html'); insertWindow.on('closed',function() { insertWindow = null; }); }

키 포인트:

  • 응용 프로그램이 시작될 때 창이 기본적으로 열리지 않도록 하려면 BrowserWindow 생성자의 options 개체에서 show 속성을 false 로 설정해야 합니다.
  • 창이 닫힌 이벤트를 발생시킬 때마다 BrowserWindow 인스턴스를 파괴해야 합니다.

"삽입" 창 열기 및 닫기

아이디어는 최종 사용자가 "메인" 창에서 버튼을 클릭할 때 "삽입" 창을 트리거할 수 있다는 것입니다. 이렇게 하려면 메인 창에서 메인 프로세스로 메시지를 보내 삽입 창을 열도록 지시해야 합니다. Electron의 IPC 모듈을 사용하여 이를 달성할 수 있습니다. 실제로 IPC 모듈에는 두 가지 변형이 있습니다.

  • 앱이 창에서 보낸 메시지를 구독할 수 있도록 하는 메인 프로세스용입니다.
  • 하나는 렌더러 프로세스를 위한 것으로 앱이 메인 ​​프로세스에 메시지를 보낼 수 있도록 합니다.

Electron의 통신 채널은 대부분 단방향이지만 원격 모듈을 사용하여 Renderer Process에서 Main Process의 IPC 모듈에 액세스할 수 있습니다. 또한 Main Process는 Event.sender.send() 메서드를 사용하여 이벤트가 발생한 Renderer Process에 메시지를 다시 보낼 수 있습니다.

IPC 모듈을 사용하려면 Main Process 스크립트의 다른 NPM 모듈처럼 필요합니다.

 var ipc = require('ipc');

... 그런 다음 on() 메서드를 사용하여 이벤트에 바인딩합니다.

 ipc.on('toggle-insert-view', function() { if(!insertWindow) { createInsertWindow(); } return (!insertWindow.isClosed() && insertWindow.isVisible()) ? insertWindow.hide() : insertWindow.show(); });

키 포인트:

  • 이벤트 이름은 원하는 대로 지정할 수 있습니다. 예는 임의적입니다.
  • BrowserWindow 인스턴스가 이미 생성되었는지 확인하고 생성하지 않은 경우 인스턴스화하는 것을 잊지 마십시오.
  • BrowserWindow 인스턴스에는 몇 가지 유용한 메서드가 있습니다.
    • isClosed() 는 창이 현재 closed 상태인지 여부에 관계없이 부울을 반환합니다.
    • isVisible() : 창이 현재 표시되는지 여부에 관계없이 부울을 반환합니다.
    • show() / hide() : 창을 표시하거나 숨기는 편리한 메서드입니다.

이제 실제로 렌더러 프로세스에서 해당 이벤트를 발생시켜야 합니다. main.view.js 라는 새 스크립트 파일을 만들고 일반 스크립트와 마찬가지로 HTML 페이지에 추가합니다.

 <script src="./main.view.js"></script>

HTML script 태그를 통해 스크립트 파일을 로드하면 클라이언트 측 컨텍스트에서 이 파일이 로드됩니다. 이것은 예를 들어 전역 변수를 window.<varname> 을 통해 사용할 수 있음을 의미합니다. 서버 측 컨텍스트에서 스크립트를 로드하려면 HTML 페이지에서 직접 require() 메서드를 사용할 수 있습니다. require('./main.controller.js'); .

스크립트가 클라이언트 측 컨텍스트에서 로드되더라도 Main Process에 대해 할 수 있는 것과 동일한 방식으로 Renderer Process에 대한 IPC 모듈에 계속 액세스할 수 있으며 다음과 같이 이벤트를 보낼 수 있습니다.

 var ipc = require('ipc'); angular .module('Utils', []) .directive('toggleInsertView', function() { return function(scope, el) { el.bind('click', function(e) { e.preventDefault(); ipc.send('toggle-insert-view'); }); }; });

이벤트를 동기적으로 보내야 하는 경우에 사용할 수 있는 sendSync() 메서드도 있습니다.

이제 "삽입" 창을 열기 위해 해야 할 일은 일치하는 Angular 지시문이 있는 HTML 버튼을 만드는 것입니다.

 <div ng-controller="MainCtrl as vm"> <button toggle-insert-view class="mdl-button"> <i class="material-icons">add</i> </button> </div>

그리고 해당 지시문을 기본 창의 Angular 컨트롤러의 종속성으로 추가합니다.

 angular .module('MainWindow', ['Utils']) .controller('MainCtrl', function() { var vm = this; }); 

비밀번호 생성

일을 단순하게 유지하기 위해 NPM uuid 모듈을 사용하여 이 튜토리얼의 목적을 위한 비밀번호 역할을 할 고유 ID를 생성할 수 있습니다. 다른 NPM 모듈처럼 설치하고 'Utils' 스크립트에서 요구한 다음 고유 ID를 반환하는 간단한 팩토리를 생성할 수 있습니다.

 var uuid = require('uuid'); angular .module('Utils', []) ... .factory('Generator', function() { return { create: function() { return uuid.v4(); } }; })

이제 삽입 뷰에 버튼을 만들고 버튼에 대한 클릭 이벤트를 수신하고 create() 메서드를 호출하는 지시문을 첨부하는 일만 남았습니다.

 <!-- in insert.html --> <button generate-password class="mdl-button">generate</button>
 // in Utils.js angular .module('Utils', []) ... .directive('generatePassword', ['Generator', function(Generator) { return function(scope, el) { el.bind('click', function(e) { e.preventDefault(); if(!scope.vm.formData) scope.vm.formData = {}; scope.vm.formData.password = Generator.create(); scope.$apply(); }); }; }])

비밀번호 저장

이 시점에서 비밀번호를 저장하려고 합니다. 비밀번호 항목의 데이터 구조는 매우 간단합니다.

 { "id": String "description": String, "username": String, "password": String }

따라서 선택적으로 백업을 위해 파일과 동기화할 수 있는 일종의 인메모리 데이터베이스만 있으면 됩니다. 이를 위해 Loki.js가 이상적인 후보로 보입니다. 이것은 이 애플리케이션의 목적에 필요한 것을 정확히 수행하고 그 위에 동적 보기 기능을 제공하여 MongoDB의 집계 모듈과 유사한 작업을 수행할 수 있도록 합니다.

Dynamic Views는 MongodDB의 Aggregation 모듈이 제공하는 모든 기능을 제공하지 않습니다. 자세한 내용은 설명서를 참조하십시오.

간단한 HTML 양식을 만드는 것으로 시작해 보겠습니다.

 <div class="insert" ng-controller="InsertCtrl as vm"> <form name="insertForm" no-validate> <fieldset ng-disabled="!vm.loaded"> <div class="mdl-textfield"> <input class="mdl-textfield__input" type="text" ng-model="vm.formData.description" required /> <label class="mdl-textfield__label" for="description">Description...</label> </div> <div class="mdl-textfield"> <input class="mdl-textfield__input" type="text" ng-model="vm.formData.username" /> <label class="mdl-textfield__label" for="username">Username...</label> </div> <div class="mdl-textfield"> <input class="mdl-textfield__input" type="password" ng-model="vm.formData.password" required /> <label class="mdl-textfield__label" for="password">Password...</label> </div> <div class=""> <button generate-password class="mdl-button">generate</button> <button toggle-insert-view class="mdl-button">cancel</button> <button save-password class="mdl-button" ng-disabled="insertForm.$invalid">save</button> </div> </fieldset> </form> </div>

이제 양식 내용의 게시 및 저장을 처리하는 JavaScript 논리를 추가해 보겠습니다.

 var loki = require('lokijs'), path = require('path'); angular .module('Utils', []) ... .service('Storage', ['$q', function($q) { this.db = new loki(path.resolve(__dirname, '../..', 'app.db')); this.collection = null; this.loaded = false; this.init = function() { var d = $q.defer(); this.reload() .then(function() { this.collection = this.db.getCollection('keychain'); d.resolve(this); }.bind(this)) .catch(function(e) { // create collection this.db.addCollection('keychain'); // save and create file this.db.saveDatabase(); this.collection = this.db.getCollection('keychain'); d.resolve(this); }.bind(this)); return d.promise; }; this.addDoc = function(data) { var d = $q.defer(); if(this.isLoaded() && this.getCollection()) { this.getCollection().insert(data); this.db.saveDatabase(); d.resolve(this.getCollection()); } else { d.reject(new Error('DB NOT READY')); } return d.promise; }; }) .directive('savePassword', ['Storage', function(Storage) { return function(scope, el) { el.bind('click', function(e) { e.preventDefault(); if(scope.vm.formData) { Storage .addDoc(scope.vm.formData) .then(function() { // reset form & close insert window scope.vm.formData = {}; ipc.send('toggle-insert-view'); }); } }); }; }])

키 포인트:

  • 먼저 데이터베이스를 초기화해야 합니다. 이 프로세스에는 Loki 개체의 새 인스턴스를 만들고, 데이터베이스 파일에 대한 경로를 인수로 제공하고, 백업 파일이 존재하는지 조회하고, 필요한 경우 생성하고('Keychain' 컬렉션 포함) 다음의 내용을 로드하는 과정이 포함됩니다. 이 파일을 메모리에 저장합니다.
  • getCollection() 메서드를 사용하여 데이터베이스에서 특정 컬렉션을 검색할 수 있습니다.
  • 컬렉션 객체는 insert() 메서드를 포함하여 여러 메서드를 노출하여 컬렉션에 새 문서를 추가할 수 있습니다.
  • 데이터베이스 내용을 파일에 유지하기 위해 Loki 객체는 saveDatabase() 메서드를 노출합니다.
  • 문서가 저장되면 양식의 데이터를 재설정하고 Main Process에 창을 닫도록 지시하는 IPC 이벤트를 보내야 합니다.

이제 새 비밀번호를 생성하고 저장할 수 있는 간단한 양식이 생겼습니다. 이 항목을 나열하기 위해 기본 보기로 돌아가 보겠습니다.

비밀번호 나열

여기서 몇 가지 일이 일어나야 합니다.

  • 컬렉션에 있는 모든 문서를 얻을 수 있어야 합니다.
  • 보기를 새로 고칠 수 있도록 새 암호가 저장될 때마다 기본 보기에 알려야 합니다.

Loki 객체에서 getCollection() 메서드를 호출하여 문서 목록을 검색할 수 있습니다. 이 메서드는 해당 컬렉션에 있는 모든 문서의 단순한 배열인 data 라는 속성을 가진 객체를 반환합니다.

 this.getCollection = function() { this.collection = this.db.getCollection('keychain'); return this.collection; }; this.getDocs = function() { return (this.getCollection()) ? this.getCollection().data : null; };

그런 다음 Angular 컨트롤러에서 getDocs()를 호출하고 초기화한 후 데이터베이스에 저장된 모든 비밀번호를 검색할 수 있습니다.

 angular .module('MainView', ['Utils']) .controller('MainCtrl', ['Storage', function(Storage) { var vm = this; vm.keychain = null; Storage .init() .then(function(db) { vm.keychain = db.getDocs(); }); });

약간의 Angular 템플릿과 비밀번호 목록이 있습니다.

 <tr ng-repeat="item in vm.keychain track by $index" class="item--{{$index}}"> <td class="mdl-data-table__cell--non-numeric">{{item.description}}</td> <td>{{item.username || 'n/a'}}</td> <td> <span ng-repeat="n in [1,2,3,4,5,6]">&bull;</span> </td> <td> <a href="#" copy-password="{{$index}}">copy</a> <a href="#" remove-password="{{item}}">remove</a> </td> </tr> 

추가된 좋은 기능은 새 암호를 삽입한 후 암호 목록을 새로 고치는 것입니다. 이를 위해 Electron의 IPC 모듈을 사용할 수 있습니다. 앞에서 언급했듯이 메인 프로세스의 IPC 모듈은 원격 모듈을 사용하여 렌더러 프로세스에서 호출되어 이를 리스너 프로세스로 전환할 수 있습니다. 다음은 main.view.js 에서 구현하는 방법에 대한 예입니다.

 var remote = require('remote'), remoteIpc = remote.require('ipc'); angular .module('MainView', ['Utils']) .controller('MainCtrl', ['Storage', function(Storage) { var vm = this; vm.keychain = null; Storage .init() .then(function(db) { vm.keychain = db.getDocs(); remoteIpc.on('update-main-view', function() { Storage .reload() .then(function() { vm.keychain = db.getDocs(); }); }); }); }]);

키 포인트:

  • Main Process에서 원격 IPC 모듈을 요구하려면 자체 require() 메서드를 통해 원격 모듈을 사용해야 합니다.
  • 그런 다음 on() 메서드를 통해 렌더러 프로세스를 이벤트 리스너로 설정하고 이러한 이벤트에 콜백 함수를 바인딩할 수 있습니다.

새 문서가 저장될 때마다 삽입 보기가 이 이벤트를 전달하는 역할을 합니다.

 Storage .addDoc(scope.vm.formData) .then(function() { // refresh list in main view ipc.send('update-main-view'); // reset form & close insert window scope.vm.formData = {}; ipc.send('toggle-insert-view'); });

비밀번호 복사

일반적으로 암호를 일반 텍스트로 표시하는 것은 좋지 않습니다. 대신 최종 사용자가 특정 항목에 대한 비밀번호를 직접 복사할 수 있도록 편의 버튼을 숨기고 제공할 것입니다.

여기서 다시 Electron은 텍스트 콘텐츠뿐만 아니라 이미지 및 HTML 코드도 복사하여 붙여넣을 수 있는 쉬운 방법을 제공하는 클립보드 모듈을 제공하여 우리를 구해 줍니다.

 var clipboard = require('clipboard'); angular .module('Utils', []) ... .directive('copyPassword', [function() { return function(scope, el, attrs) { el.bind('click', function(e) { e.preventDefault(); var text = (scope.vm.keychain[attrs.copyPassword]) ? scope.vm.keychain[attrs.copyPassword].password : ''; // atom's clipboard module clipboard.clear(); clipboard.writeText(text); }); }; }]);

생성된 암호는 간단한 문자열이므로 writeText() 메서드를 사용하여 암호를 시스템의 클립보드에 복사할 수 있습니다. 그런 다음 기본 보기 HTML을 업데이트하고 copy-password 지시문이 있는 복사 버튼을 추가하여 암호 배열의 인덱스를 제공할 수 있습니다.

 <a href="#" copy-password="{{$index}}">copy</a>

비밀번호 제거

우리의 최종 사용자는 암호가 더 이상 사용되지 않는 경우 암호를 삭제할 수 있기를 원할 수도 있습니다. 이렇게 하려면 키체인 컬렉션에서 remove() 메서드를 호출하기만 하면 됩니다. 다음과 같이 'remove()' 메서드에 전체 문서를 제공해야 합니다.

 this.removeDoc = function(doc) { return function() { var d = $q.defer(); if(this.isLoaded() && this.getCollection()) { // remove the doc from the collection & persist changes this.getCollection().remove(doc); this.db.saveDatabase(); // inform the insert view that the db content has changed ipc.send('reload-insert-view'); d.resolve(true); } else { d.reject(new Error('DB NOT READY')); } return d.promise; }.bind(this); };

Loki.js 문서에는 ID로 문서를 제거할 수도 있다고 나와 있지만 예상대로 작동하지 않는 것 같습니다.

데스크탑 메뉴 생성

Electron은 OS 데스크탑 환경과 원활하게 통합되어 앱에 "기본" 사용자 경험 모양과 느낌을 제공합니다. 따라서 Electron은 앱을 위한 복잡한 데스크탑 메뉴 구조를 만드는 데 전념하는 메뉴 모듈과 함께 번들로 제공됩니다.

메뉴 모듈은 방대한 주제이며 거의 자체 튜토리얼이 필요합니다. 이 모듈의 모든 기능을 알아보려면 Electron의 데스크탑 환경 통합 튜토리얼을 읽어보시기 바랍니다.

이 현재 자습서의 범위에 대해 사용자 지정 메뉴를 만들고 사용자 지정 명령을 추가하고 표준 종료 명령을 구현하는 방법을 볼 것입니다.

앱에 사용자 정의 메뉴 생성 및 할당

일반적으로 Electron 메뉴에 대한 JavaScript 로직은 앱의 메인 스크립트 파일에 속하며 여기에서 메인 프로세스가 정의됩니다. 그러나 별도의 파일로 추상화하고 원격 모듈을 통해 메뉴 모듈에 액세스할 수 있습니다.

 var remote = require('remote'), Menu = remote.require('menu');

간단한 메뉴를 정의하려면 buildFromTemplate() 메서드를 사용해야 합니다.

 var appMenu = Menu.buildFromTemplate([ { label: 'Electron', submenu: [{ label: 'Credits', click: function() { alert('Built with Electron & Loki.js.'); } }] } ]);

배열의 첫 번째 항목은 항상 "기본" 메뉴 항목으로 사용됩니다.

label 속성의 값은 기본 메뉴 항목에 대해별로 중요하지 않습니다. 개발 모드에서는 항상 Electron 을 표시합니다. 나중에 빌드 단계에서 기본 메뉴 항목에 사용자 지정 이름을 할당하는 방법을 볼 것입니다.

마지막으로 setApplicationMenu() 메서드를 사용하여 이 사용자 지정 메뉴를 앱의 기본 메뉴로 할당해야 합니다.

 Menu.setApplicationMenu(appMenu);

키보드 단축키 매핑

Electron은 Command+A 또는 Ctrl+Shift+Z 와 같이 실제 키보드 조합에 매핑되는 미리 정의된 문자열 세트인 "가속기"를 제공합니다.

Command 가속기는 Windows 또는 Linux에서 작동하지 않습니다. 암호 키체인 응용 프로그램의 경우 두 가지 명령을 제공하는 File 메뉴 항목을 추가해야 합니다.

  • 암호 생성 : Cmd(또는 Ctrl) + N 으로 삽입 보기를 엽니다.
  • 종료 : Cmd(또는 Ctrl) + Q 로 앱을 완전히 종료합니다.
 ... { label: 'File', submenu: [ { label: 'Create Password', accelerator: 'CmdOrCtrl+N', click: function() { ipc.send('toggle-insert-view'); } }, { type: 'separator' // to create a visual separator }, { label: 'Quit', accelerator: 'CmdOrCtrl+Q', selector: 'terminate:' // OS X only!!! } ] } ...

키 포인트:

  • type 속성이 separator 로 설정된 배열에 항목을 추가하여 시각적 구분 기호를 추가할 수 있습니다.
  • CmdOrCtrl 가속기는 Mac 및 PC 키보드와 모두 호환됩니다.
  • selector 속성은 OSX와만 호환됩니다!

앱 스타일링

다양한 코드 예제에서 mdl- 로 시작하는 클래스 이름에 대한 참조를 발견했을 것입니다. 이 튜토리얼의 목적을 위해 저는 Material Design Lite UI 프레임워크를 사용하기로 선택했지만 원하는 UI 프레임워크를 자유롭게 사용하십시오.

HTML5로 할 수 있는 모든 것은 Electron에서 할 수 있습니다. 앱 바이너리의 크기가 커지고 타사 라이브러리를 너무 많이 사용하는 경우 발생할 수 있는 결과적인 성능 문제를 염두에 두십시오.

배포용 전자 앱 패키징

Electron 앱을 만들었습니다. 보기에 좋고, Selenium과 WebDriver로 e2e 테스트를 작성했으며, 이를 전 세계에 배포할 준비가 되었습니다!

그러나 여전히 개인화하고 기본 "Electron"이 아닌 사용자 정의 이름을 지정하고 Mac 및 PC 플랫폼 모두에 대한 사용자 정의 응용 프로그램 아이콘을 제공할 수도 있습니다.

Gulp로 빌드하기

요즘에는 생각할 수 있는 모든 것을 위한 Gulp 플러그인이 있습니다. Google에 gulp electron 을 입력하기만 하면 gulp-electron 플러그인이 있을 것입니다!

이 플러그인은 이 튜토리얼의 시작 부분에서 자세히 설명된 폴더 구조가 유지되는 한 사용하기가 상당히 쉽습니다. 그렇지 않다면 물건을 조금 옮겨야 할 수도 있습니다.

이 플러그인은 다른 Gulp 플러그인처럼 설치할 수 있습니다.

 $ npm install gulp-electron --save-dev

그런 다음 Gulp 작업을 다음과 같이 정의할 수 있습니다.

 var gulp = require('gulp'), electron = require('gulp-electron'), info = require('./src/package.json'); gulp.task('electron', function() { gulp.src("") .pipe(electron({ src: './src', packageJson: info, release: './dist', cache: './cache', version: 'v0.31.2', packaging: true, platforms: ['win32-ia32', 'darwin-x64'], platformResources: { darwin: { CFBundleDisplayName: info.name, CFBundleIdentifier: info.bundle, CFBundleName: info.name, CFBundleVersion: info.version }, win: { "version-string": info.version, "file-version": info.version, "product-version": info.version } } })) .pipe(gulp.dest("")); });

키 포인트:

  • src/ 폴더는 Gulpfile.js가 있는 폴더와 같거나 배포 폴더와 같은 폴더일 수 없습니다.
  • platforms 배열을 통해 내보내려는 플랫폼을 정의할 수 있습니다.
  • Electron 바이너리가 다운로드될 cache 폴더를 정의해야 앱과 함께 패키징할 수 있습니다.
  • 앱의 package.json 파일 내용은 packageJson 속성을 통해 gulp 작업에 전달되어야 합니다.
  • 선택적 packaging 속성이 있어 생성된 앱의 zip 아카이브도 생성할 수 있습니다.
  • 각 플랫폼에 대해 정의할 수 있는 "플랫폼 리소스" 집합이 다릅니다.

앱 아이콘 추가

platformResources 속성 중 하나는 icon 속성으로, 앱에 대한 사용자 지정 아이콘을 정의할 수 있습니다.

 "icon": "keychain.ico"

OS X에는 .icns 파일 확장자를 가진 아이콘이 필요합니다. .png 파일을 .ico.icns 로 무료로 변환할 수 있는 여러 온라인 도구가 있습니다.

결론

이 기사에서 우리는 Electron이 실제로 할 수 있는 일의 표면만 긁었습니다. Atom 또는 Slack과 같은 훌륭한 앱을 이 도구와 함께 사용할 수 있는 영감의 원천으로 생각하십시오.

이 튜토리얼이 유용했기를 바랍니다. 자유롭게 의견을 남기고 Electron에 대한 경험을 공유해 주세요!