アカベコマイリ

HEAR NOTHING SEE NOTHING SAY NOTHING

Electron を試す 5 - Electron v0.35.0 対応

November 27, 2015開発Electron, JavaScript, Node

Electron v0.35.0 で互換に影響のある変更が入ったため、その対応についてまとめる。既に v0.35.1 もリリースされているけれど、こちらは大きな変更がないため今回は取り扱わない。

v0.35.0 Release Notes

まずは Electron v0.35.0 の Release Notes を確認。

ざっくり意訳。

共通

  • Show warnings for deprecated APIs, can be turned off with process.noDeprecation.

    • 非推奨の API に対して警告を表示するようにした
    • この警告を無効化する場合は process.noDeprecation を指定すること
  • Add electron module which includes all public APIs.

    • electron モジュールを追加して public な API はそこへ含めるようにした
  • The ipc module is deprecated, should use ipcRenderer in renderer process, and ipcMain in main process.

    • ipc モジュールを非推奨にした
    • かわりに Renderer プロセスでは ipcRenderer、Main プロセスは ipcMain を使用すること
  • The ipcRenderer module adds an event object when emitting events, to match the style of ipcMain module.

    • ipcRenderer のイベント ハンドラーに event オブジェクトを追加した
    • この対応により ipcMain と設計 ( インターフェース ) が等しくなる
  • Remove the - in BrowserWindow's option names.

    • BrowserWindow のオプション名から - を削除した
  • clicked events in Tray are renamed to click.

    • Tray イベントの clickedclick に名称変更した
  • The Url in API names is replaced with URL.

    • API 名の Url という表記を URL に置き換えた
  • Add documents, downloads, music, pictures, videos keys to app.getPath.

    • app.getPath のキーに documentsdownloadsmusicpicturesvideos を追加
  • Fix memory leak of webContents.beginFrameSubscription.

    • webContents.beginFrameSubscription のメモリー リークを修正した

Windows

  • Add support for toast notifications on Windows >= 8.

OS X

  • Add drag-enter, drag-leave, drag-end and drop events to Tray module.

    • Tray モジュールのイベントに drag-enterdrag-leavedrag-enddrop を追加した
  • Fix images not showing in notifications on OS X 10.9.

    • OS X 10.9 の通知機能で画像が表示されない問題を修正

対応

各種変更の詳細と対応方法をまとめる。

非推奨 API の警告

非推奨の API の使用が警告されるようになった。例えば BrowserWindow.loadUrl を呼び出すと以下のように警告される。

(electron) loadUrl is deprecated. Use loadURL instead.

対象となる API は廃止される可能性が高いので早期に修正すること。警告を抑止するなら Main プロセス冒頭で process.noDeprecationtrue を代入すればよい。

process.noDeprecation = true;

この対応により警告が抑止されることを確認。しかし警告はアプリを修正するための重要なヒントであり、表示による動作への影響もないため抑止しないほうがよいだろう。

public API の electron モジュール移行

electron モジュールが追加され公開 API はそちらに移行された。もしくはされる。これまで私が使用してきたものだと ipcshell が対象になっている。

個別の API リファレンスに掲載されているサンプルでは変更後のコードになっているため、ひととおり目を通しておいたほうがよい。electron 移行にともない参照方法も変更されている。require を利用するなら electron 配下から読み込む。

const ipcMain = require( 'electron' ).ipcMain;

Modules 形式ならば electron に対して明示的に名前指定すればよい。

import { ipcMain } from 'electron';

私は Modules 形式を利用するときの命名を PascalCase にしている。しかし ipcMain などは camelCase となるため一貫性が崩れる。またユニット テストで IPC や Shell API をモック化したくなるかもしれない。そのためこれらは require 形式で読み込み、その参照を従属するインスタンスに伝搬する方式で設計している。

import DialogManager from './DialogManager.js';
import WindowManager from './WindowManager.js';

class Main {
  constructor() {
    // 共有される標準 API
    this._ipc   = require( 'electron' ).ipcMain;
    this._shell = require( 'electron' ).shell;

    // this を渡すことで従属するインスタンスは間接的に API を参照する
    this._windowManager = new WindowManager( this );
    this._dialogManager = new DialogManager( this );
  }
}

徹底するなら AppBrowserWindow なども間接参照にするべきだが、とりあえずは electron 配下のものだけにしている。

ipc モジュールから ipcMainipcRenderer への移行ipc

モジュールが非推奨になった。代りに Main プロセスは ipcMain、Renderer プロセスでは ipcRenderer を使用する。

const ipcMain = require( 'electron' ).ipcMain;

ipcMain.on( 'asynchronous-message', ( ev, arg ) => {
  console.log( arg );  // prints "ping"
  ev.sender.send( 'asynchronous-reply', 'pong' );
} );

ipcMain.on( 'synchronous-message', ( ev, arg ) => {
  console.log( arg );  // prints "ping"
  ev.returnValue = 'pong';
} );

ipcRenderer はイベント ハンドラも変更されている。従来は

ipc.on( 'message', ( arg ) => {
} );

となっていたが新ハンドラは第一引数にイベント オブジェクトを取る。インターフェース設計が Main/Renderer プロセスで統一されて分かりやすくなった。

ipcRenderer.on( 'requsetMessage', ( ev, arg ) => {
  ev.sender.send( 'responseMessage', 'I am a Renderer' );

従来は Renderer プロセスのハンドラから Main プロセスに返信したいなら通常の send を利用していた。新ハンドラでは Main プロセスと同様にイベント オブジェクトの sender 経由で直に返信できる。

BrowserWindow のオプションと API 名の変更

BrowserWindow のオプション名から - が取り除かれた。例えば max-widthmaxWidth になっている。リファレンス を確認すると chain-case だったものは camelCase へ改められたようだ。chain-case だと JavaScript のオブジェクト名をクォートする必要があり面倒。また chain-case とそうではないものがオブジェクト内に混在しているときにクォートで統一すべきか悩んだものだが、こうした問題が解消された。

API 名の Url という表記が URL に変更されている。代表的なものだと BrowserWindows の loadUrlloadURL になった。

BrowserWindow の新しいオプション名については - で検索してリファレンスを確認しながら置き換えてゆく。API 名については loadUrl の場合、非推奨とマークされているようで警告される。とはいえ、全 API がこうなっているか分からないので Url で検索して個別対応するのが無難だろう。

特殊フォルダーの追加

app.getPath で取得可能な特殊フォルダーが大量に追加された。これらはプラットフォーム標準のファイル置き場。ファイル操作の際 dialog.showOpenDialogdefaultPath へ指定するなどの用途が考えられる。

リファレンスにキー単位でフォルダの解説が掲載されているけれど、現時点では Windows のものだけ。よって実際に得られるパスを調べるため、Main プロセスで以下の関数を実行してみた。

function getPathSample() {
  console.log( 'documents:', App.getPath( 'documents' ) );
  console.log( 'downloads:', App.getPath( 'downloads' ) );
  console.log( 'music:',     App.getPath( 'music' ) );
  console.log( 'pictures:',  App.getPath( 'pictures' ) );
  console.log( 'videos:',    App.getPath( 'videos' ) );
}

OS X El Capitan 10.11.1 上の実行結果は以下。XXXX 部分はログインしているユーザー名。

documents: /Users/XXXX/Documents
downloads: /Users/XXXX/Downloads
music: /Users/XXXX/Music
pictures: /Users/XXXX/Pictures
videos: /Users/XXXX/Movies

Windows 8.1 での実行結果は以下となった。

documents: C:\Users\XXXX\Documents
downloads: C:\Users\XXXX\Downloads
music: C:\Users\XXXX\Music
pictures: C:\Users\XXXX\Pictures
videos: C:\Users\XXXX\Videos

OS X と Windows ならば追加されたフォルダーすべてのパスを得られた。Linux は試していない。Linux はディストリビューション間で特殊フォルダーの定義が統一されているも不明なのでパスを得られないかもしれない。

その他

その他の変更はバグ修正や普段あまり使わない機能に関するものなので割愛。

サンプル プロジェクト

今回の対応を実施したサンプル プロジェクトを公開。