2019年2月3日日曜日

electron 超入門

概要

electron は HTML と JavaScript でデスクトップアプリケーションを作成することができるフレームワークです
今回は簡単な使い方とサンプルを紹介します
また基本となるメインプロセスとレンダラープロセス間で通信するための IPC にも触れます

環境

  • macOS 10.14.2
  • node 10.1.0
  • electron 4.0.3

electron インストール

  • vim package.json
{
  "name": "try_electron",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "start": "electron ."
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "electron": "^4.0.3"
  }
}
  • npm install --save

Hello World

main.js でウィンドウの表示やイベントの登録を行います
main.js の処理はメインプロセスと呼ばれる処理で外部のサイトへの通信などバックエンドで行う重たい処理などを行います

  • vim main.js
const { app, BrowserWindow } = require('electron')

let win

function createWindow () {
    win = new BrowserWindow({ width: 800, height: 600 })
    win.loadFile('index.html')
    win.webContents.openDevTools()
    win.on('closed', () => {
    win = null
    })
}

app.on('ready', createWindow)
app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
    app.quit()
    }
})
app.on('activate', () => {
    if (win == null) {
    createWindow()
    }
})
  • vim index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
  </head>
  <body>
    <h1>Hello World!</h1>
    We are using node <script>document.write(process.versions.node)</script>,
    Chrome <script>document.write(process.versions.chrome)</script>,
    and Electron <script>document.write(process.versions.electron)</script>.
  </body>
</html>

実行してみましょう
以下のようにアプリが立ち上がれば OK です

  • npm start

トラブルシューティング

Cannot read property 'on' of undefined というエラーが出ることがありました
自分の場合原因は package.json の start コマンドを node コマンドで実行していたことが原因でした

"scripts": {
  "start": "node ."
}

"scripts": {
  "start": "electron ."
}

ボタンを作って見る

main.js はそのままです
HTML 上にボタンを配置して別の JS で DOM 操作するだけです

  • vim index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Button Event</title>
  </head>
  <body>
    <h1>Button Event</h1>
    <input type="text" id="input1" size="30">
    <button type="button" id="button1">submit</button>
    <script type="text/javascript" src="lib.js"></script>
  </body>
</html>

新たに lib.js が登場しました
これがレンダラープロセス側で実行される JavaScript になります
普通に Web アプリを作るように主に DOM の操作を行います

  • vim lib.js
let button = document.getElementById('button1')
button.onclick = function() {
    let input = document.getElementById('input1')
    console.log(input.value)
}

実行すると以下のように動作します

IPC 通信

electron はメインプロセス (main.js) とレンダラープロセス (lib.js) に分かれています
それぞれでデータのやり取りを行うには IPC というモジュールを使います

main.js は ipcMain を使うように修正します
またレンダラープロセスから送られた来たイベントをハンドリングするハンドラ (ipc.on) を追加します

  • vim main.js
const { app, BrowserWindow } = require('electron')
const ipc = require('electron').ipcMain

let win

function createWindow () {
    win = new BrowserWindow({ width: 800, height: 600 })
    win.loadFile('index.html')
    win.webContents.openDevTools()
    win.on('closed', () => {
    win = null
    })
}

app.on('ready', createWindow)
app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
    app.quit()
    }
})
app.on('activate', () => {
    if (win == null) {
    createWindow()
    }
})

ipc.on('test', function (event, _) {
    event.sender.send('test-reply', 'pong')
})

レンダラー側は ipcRenderer を使ってメイン側にリクエストするイメージです
コールバック関数で結果を受け取ったら DOM 操作なりをすれば OK です

  • vim lib.js
const ipc = require('electron').ipcRenderer
ipc.send('test', 'ping')
ipc.on('test-reply', function (event, arg) {
    document.getElementById("ret").innerHTML = arg
})
  • vim index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>IPC Test</title>
  </head>
  <body>
    <h1>IPC Test</h1>
    <h2 id="ret"></h2>
    <script type="text/javascript" src="lib.js"></script>
  </body>
</html>

結果は以下のような感じになります

外部のサイトにアクセスする

IPC を使ってメインプロセス側で行います
また electron には ClientRequest というクラスがありこれを使って外部のサイトにアクセスすることができます

main.js では IPC のハンドリング後外部サイトにアクセスするようにします
またそのレスポンスをレンダラー側に返却する処理も実装します

  • vim main.js
const { app, BrowserWindow } = require('electron')
const ipc = require('electron').ipcMain
const net = require('electron').net

let win

function createWindow () {
    win = new BrowserWindow({ width: 800, height: 600 })
    win.loadFile('index.html')
    win.webContents.openDevTools()
    win.on('closed', () => {
    win = null
    })
}

app.on('ready', createWindow)
app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
    app.quit()
    }
})
app.on('activate', () => {
    if (win == null) {
    createWindow()
    }
})

ipc.on('check', function (event, arg) {
    const request = net.request({
    method: 'GET',
    protocol: 'https:',
    hostname: arg,
    port: 443,
    path: '/'
    })
    request.on('response', (response) => {
    event.sender.send('check-reply', response.statusCode)
    response.on('error', (error) => {
        console.log(`ERROR: ${JSON.stringify(error)}`)
    })
    })
    request.end()
})

net.request でリクエストを生成 request に対してレスポンスをハンドリングするためのイベントハンドラを登録、そして request.end() で実際にリクエストをコールします
結果をハンドラで受け取ったら IPC を使って結果をレンダラーに渡します

レンダラー側はボタンを押したら github.com のステータスを取得してもらうようにメイン側に依頼します

  • vim lib.js
let button = document.getElementById('button1').onclick = function() {
    const ipc = require('electron').ipcRenderer
    ipc.send('check', 'github.com')
    ipc.on('check-reply', function (event, arg) {
    document.getElementById("ret").innerHTML = arg
    })
}
  • vim index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Github Status</title>
  </head>
  <body>
    <h1>Github Status</h1>
    <button type="button" id="button1">check</button>
    <h2 id="ret"></h2>
    <script type="text/javascript" src="lib.js"></script>
  </body>
</html>

これで実行しボタンをクリックすると github.com にアクセスしレスポンスコードを表示してくれます

パッケージング

もし各プラットフォームで配布する場合には指定のフォーマットにパッケージングする必要があります
便利な electron-packager というツールがあるのでそれを使いましょう

  • npm install electron-packager --save-dev

インストールはこれで完了です
package.json の package というコマンドを追加しましょう

  • vim package.json
{
  "name": "try_electron",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "start": "electron .",
    "package": "electron-packager . test --platform=darwin --arch=x64 --app-version=1.0.0"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "electron": "^4.0.3",
    "electron-packager": "^13.0.1"
  }
}

あとは実行するだけです

  • npm run package

完了すると xxxx-darwin-x64 というディレクトリが作成されます
今回であれば test-darwin-x64 です
xxxx.app というファイルが直下にあるのでそれを Applications 配下に配置すればインストール完了です
また Windows 用にパッケージングしたい場合は platform オプションに win32 を追加します

最後に

electron に入門してみました
最低限の electron のアーキテクチャや API を覚える必要はありますが、ほぼ UI などはほぼ Web を開発する方法と同じ感覚で開発できるのは嬉しい点かなと思います
HTML/JavaScript なので何も考えずマルチプラットフォームで開発できるのも嬉しい点かなと思います

参考サイト

0 件のコメント:

コメントを投稿