特集
» 2015年12月04日 05時00分 公開

.NET開発者のためのJavaScriptライブラリカタログ(デスクトップアプリ編)特集:今から始めるJavaScriptアプリ開発(2/3 ページ)

[かわさきしんじ,Insider.NET編集部]

プロセス間通信を行ってみる

 次に、メインプロセスとレンダラープロセスとの間で、プロセス間通信を行ってみよう。Electronでプロセス間通信を行うには二つの手段がある。一つはipcMain/ipcRendererモジュールを使用するもの。もう一つはより簡便にプロセス間通信を行えるremoteモジュールを使用するものだ。

 最初にipcMain/ipcRendererモジュールを使って、テキストボックスに入力された値をメインプロセスに送信する例とremoteモジュールを使用してレンダラープロセスからダイアログを表示する例を見てみよう。

 index.htmlとapp.jsファイルを次のように変更する。ボタンを三つ追加して、FooControllerクラスのメソッドと結び付けているだけだ。

<!DOCTYPE html>
<html ng-app="myapp">
  …… 省略 ……
<body>
  …… 省略 ……
  <div ng-controller="FooController as fooctrl">
    <p>
    <input type="text" ng-model="fooctrl.test" />
    {{ fooctrl.test }}
    </p>
    <button ng-click="fooctrl.send()">send async</button>
    <button ng-click="fooctrl.sendsync()">send sync</button>
    <button ng-click="fooctrl.showdialog()">show dialog</button>
  </div>
</body>
</html>

…… 省略 ……
var ipcRenderer = electron.ipcRenderer;
var dialog = electron.remote.dialog;

app.controller('FooController', function() {
  this.test = "foobar";
  this.send = function() {
    ipcRenderer.send('asynchronous-message', this.test);
  };
  this.sendsync = function() {
    console.log(ipcRenderer.sendSync('synchronous-message', this.test));
  };
  this.showdialog = function() {
    dialog.showMessageBox({
      type: "info",
      title: "Info",
      message: "hello from renderer proc",
      buttons: ["OK"]
    });
  };
});

変更後のindex.htmlファイルとapp.jsファイル
showMessageBoxメソッド呼び出しではボタンは最低でも一つ必要なようだ。

 HTMLファイルの説明は不要だろう。以下では、app.jsファイルに注目していく。

 レンダラープロセス(メインプロセスで作成されたWebページ側)からプロセス間通信を行うにはipcRendererモジュールを使用する。あるいはremoteモジュールを介して、メインプロセスが提供する機能を使用する。これを行っているのが最初の2行だ。

 メインプロセスへの送信を非同期に行うにはipcRenderer.sendメソッドを使用する。これはメインプロセスへのデータを送ったら、そこでメソッド呼び出しは終了する。

 同期的に通信するにはipcRenderer.sendSyncメソッドを使用する。ただし、こちらはメインプロセスからの返信が到着するまでWebページの動作をブロックするので注意が必要だ(メインプロセスから返された値がsendSyncメソッドの戻り値となる。従って、上のコードではメインプロセスから返された値がconsole.logメソッドにより出力される)。

 send/sendSyncメソッドの第1引数プロセス間通信に使用する「チャネル」、第2引数は送信データである。

 ダイアログ表示コードは後で見るとして、指定された二つのチャネルで待ち受けるメインプロセスのコードは次のようになる。

var electron = require('electron');
var app = electron.app;
var BrowserWindow = electron.BrowserWindow;
var ipcMain = electron.ipcMain;

…… 省略 ……

ipcMain.on('asynchronous-message', function(e, arg) {
  console.log('asynchronous msg: ' + arg);
});

ipcMain.on('synchronous-message', function(e, arg) {
  console.log('synchronous msg: ' + arg);
  e.returnValue = 'returned from send sync';
});

main.jsファイル(JavaScript)

 メイン側ではipcMain.onメソッドを使用して、イベントを待ち受ける。第1引数には先ほど見た「チャネル」を指定する。レンダラープロセスからメッセージが送信されたときには、第2引数に指定した無名関数で処理が行われる。この関数にはイベント情報を含むオブジェクトが渡されるが、同期通信では、このオブジェクトのreturnValueプロパティに値をセットすることで、ブロックしていたsendSyncメソッドが終了する(ここでは「returned from send sync」を設定している)。

 アプリを実行すると次のようになる。

メインプロセスとレンダラープロセスのプロセス間通信 メインプロセスとレンダラープロセスのプロセス間通信
(1) レンダラープロセスが非同期にメッセージを送信。
(2) 非同期に送信されたメッセージをメインプロセスがコンソールに出力。
(3) レンダラープロセスが同期的にメッセージを送信。
(4) 同期的に送信されたメッセージをメインプロセスがコンソールに出力。
(5) メインプロセスから返された値を、レンダラープロセスがコンソールに出力。

 最後にダイアログを表示するコードを再掲しておこう。

…… 省略 ……
var dialog = electron.remote.dialog;

app.controller('FooController', function() {
  …… 省略 ……
  this.showdialog = function() {
    dialog.showMessageBox({
      type: "info",
      title: "Info",
      message: "hello from renderer proc",
      buttons: ["OK"]
    });
  };
});

remoteモジュールを使って、レンダラープロセスからダイアログを表示

 先ほども述べたが、レンダラープロセスからはネイティブなUIを直接操作できない。Electronのremoteモジュールを使用すると、上で見たような生なプロセス間通信を行わずに、メインプロセスが所有するオブジェクトを遠隔的に使用できる。ここでは、「remote.dialog」オブジェクトのshowMessageBoxメソッドに情報を適宜指定して呼び出しているだけだ。ただし、複数のOSが手元にある方は実際に試してみると分かるが、OSごとに異なるUIが表示される。

 このように、Electronを使うと、Web標準技術を使って、OSごとに固有なGUIを活用したネイティブアプリを容易に開発できる。また、Electronではメインプロセスとレンダラープロセスの2種類のプロセスがあり、それぞれが可能なこと/不可能なことが明確に別れている。明快なフレームワーク設計だが、プロセス間で情報をやり取りするには通信を行う必要がある。

 だいぶ長くなってしまったので、NW.jsについては簡単に触れるに留めておこう。

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。