ElectronのBrowserWindow間で直接メッセージをやりとりする

最近、社内でLT(https://labs.gree.jp/blog/2018/10/17291/)があって、そこで話をしたので、その時の内容を書く。
これは、その一部の話。

経緯とか要約とか

複数立ち上げたBrowserWindowのインスタンス間でメッセージをやりとりする。
社内のメモで出来ない。いったん、main processを経由しないといけない、と書いている人が居たので、
ちょっと書いたのであった。

説明

ウィンドウ間でメッセージをやりとりするには、
main processをいったん経由してから、
他のrenderer processにメッセージを送るのが作法のような気がするが


どうにかして、BrowserWindowのインスタンスを取得すれば、
各ウィンドウ間で直接データをやりとりできる。

具体的な実装の例

// https://github.com/taku-o/hello-electron-003-to-sub-msg/blob/master/electron.ts
mainWindow = new BrowserWindow({
    width: 600,
    height: 600,
    acceptFirstMouse: true,
    show: true
});
mainWindow.loadURL(`file://${__dirname}/main.html`);
// !!!!
global.mainWindow = mainWindow;
  • メッセージを投げる側の例
// https://github.com/taku-o/hello-electron-003-to-sub-msg/blob/master/js/main.ts
$scope.sendMsgTo1stWindow = function() {
    // remoteは参照そのものではなく、呼んだ瞬間のコピーのような
    const firstWindow = require(‘electron').remote.getGlobal('firstWindow');                  
    firstWindow.webContents.send('message', 'message from main.');
};
  • メッセージを受ける側の例
// https://github.com/taku-o/hello-electron-003-to-sub-msg/blob/master/js/second.ts
var ipcRenderer = require('electron').ipcRenderer;

// recieve message
$scope.message = '';
ipcRenderer.on('message', (event, message: string) => {
    $scope.message = message;
    $timeout(() => { $scope.$apply(); });
});

こんなに短いサンプルコードなのに、angularやtypescript使っていてわかりにくいとか、
global使うのは反則ではないのか?
とかあるかもしれないけど、あまり細かいことは気にしないで欲しい。

"できる"と"やる"は別の話

でも、結局は、main processで、BrowserWindowのインスタンスを管理することになると思います。
だいたい設計的な理由で。その方がいろいろ利点があるはず。

  • BrowserWindowのインスタンスを管理する場所を散らばらせるのは良くない
  • メニューとかにBrowserWindowのインスタンスを渡せると、処理上、都合の良い場合が多い。

サンプルコード

今回の実験のために作ったサンプルコードです。