techium

このブログは何かに追われないと頑張れない人たちが週一更新をノルマに技術情報を発信するブログです。もし何か調査して欲しい内容がありましたら、@kobashinG or @muchiki0226 までいただけますと気が向いたら調査するかもしれません。

ElectronでBrowserWindowと通信する(ipc編)

Electronでアプリを開発している際にBrowserWindowを生成している処理部とBrowserWindowのhtml上でと通信したいことが多々あります。
そこでElectronではプロセス間通信を用いて通信し、処理を受け渡すことが可能です。
そのやり方についてご説明いたします。
また、なぜプロセス間通信なのかという部分もこの後ご説明していきます。

プロセス間通信

ElectronではBrowserWindowを生成する側でappの制御を行う処理をメインプロセス(main process)。 BrowserWindowをappが生成して動作するプロセスをレンダラープロセス(renderer process)と呼ばれます。 メインプロセスは一つしかプロセスが存在しないのですが、レンダラープロセスはBrowserWindowが複数生成された際に複数のプロセスを持つことになります。
これはもともとElectronはnode.jsとChromiumの思想を融合した代物ためChromiumプロジェクトのアーキテクチャに則った作りになっています。
Chromiumではブラウザのメインとなる処理は1つのプロセスで生成し、各タブを別プロセスを管理されています。 別プロセスになっているのは各タブでプロセスがダウンした場合にまとめてアプリがダウンしないような仕組みを取るために組み込まれたと言われています。
その各タブとメインの処理の通信はプロセス間通信を行いそれぞれで処理を実施する仕組みが入っています。

f:id:muchiki0226:20160320215857p:plain:w400

その機能を利用した機能としてElectronは次の機能でプロセス間通信を可能にしています。

  • ipc
  • remote

ここではipcの使い方をご説明します。

レンダラープロセスからメインプロセスへのプロセス間通信(ipc)

レンダラープロセスからプロセス間通信を行ってメインプロセスに処理をさせる場合次の2種類の方法があります。

  • 非同期通信
  • 同期通信

それぞれの使い方を説明します。

非同期通信

非同期通信を利用するにはレンダラープロセス側を次のように書きます。

Electronでプロセス間通信(ipc) RendererProcessからMainProcessへ非 ...

index.htmlの7行目でElectronのipcのインスタンスを取得し、15行目でsendを実施しています。
sendは非同期でメインプロセスにメッセージを送るAPIになっており、 第1引数のイベント名で第2引数のメッセージの送信を行います。
また、メインプロセス側にメッセージを送ってそのメッセージが返信されてくる場合は12行目のようにonを使ってメインプロセス側のメッセージの返信イベントを受け取れるようにします。

main.jsでは1行目でipcのインスタンスを取得し、4行目のipc.onで特定のイベントが来た時の処理を記載しています。
第1引数ではレンダラープロセス側で指定したイベント名と同じ名前で指定すればそのイベント名が発生した時に第2引数の処理を実施してくれます。
第2引数のfunctionの第2引数はそのイベントで付与されたメッセージが収められているのでそれを取得することができます。
非同期通信のためそのまま値を返り値で返信することはできないためfunctionの第1引数のsender.sendを利用することでレンダラープロセスへメッセージが送ることが可能です。

上記のコードを実行した際は次のような結果が返ってきます。

メインプロセス側のログ
asynchronous-message arg : asynchronous-message renderer process.
レンダラープロセス側のログ
asynchronousMessage
synchronousMessage response : asynchronous-message main process.

同期通信

同期通信を利用するにはレンダラープロセス側を次のように書きます。

Electronでプロセス間通信(ipc) RendererProcessからMainProcessへ同 ...

index.htmlの7行目でElectronのipcのインスタンスを取得し、11行目でsendSyncを実施しています。
sendSyncは同期でメインプロセスにメッセージを送るAPIになっており、 第1引数のイベント名で第2引数のメッセージの送信を行います。
その返り値にメインプロセスが設定したメッセージが返信されてきます。

main.jsでは1行目でipcのインスタンスを取得し、4行目のipc.onで特定のイベントが来た時の処理を記載しています。
第1引数ではレンダラープロセス側で指定したイベント名と同じ名前で指定すればそのイベント名が発生した時に第2引数の処理を実施してくれます。
第2引数のfunctionの第2引数はそのイベントで付与されたメッセージが収められているのでそれを取得することができます。
functionの第1引数のreturnValueに返却したいメッセージを入れるとメインプロセス側での処理が終了し、レンダラープロセスに処理が移行した時に返り値で設定した値が取得できるようになります。

上記のコードを実行した際は次のような結果が返ってきます。

メインプロセス側のログ
synchronous-message arg : synchronous-message renderer process.
レンダラープロセス側のログ
synchronousMessage
synchronousMessage response : synchronous-message main process.

メインプロセスからレンダラープロセスへのプロセス間通信(ipc)

メインプロセスからレンダラープロセスへプロセス間通信を実施する場合は非同期でのプロセス間通信しかできません。 プロセス間通信の仕方は次のようになります。

Electronでプロセス間通信(ipc) MainProcessからRendererProcessへ非 ...

ここのmain.jsではTrayを利用してタスクバーのicon.pngをクリックしてasynchronousという項目を選択した時にレンダラープロセスへメッセージを送るようにしています。 main.jsの18行目のところでmainWindowはプロセス間通信を行いたいBrowserWindowに対してwebContents.sendで送るイベント名とメッセージをセットしてプロセス間通信を実施しています。

レンダラープロセス側では9行目でwebContents.sendで設定されたイベント名と同じイベントが発生した際に処理を受け取れるようにonでコールバックを設定しています。 その第2引数のfunctionの引数でメインプロセスで設定したメッセージを受け取ることができます。

サンプルコード

github.com