💫

ElectronのContextBridge

2021/06/30に公開

Electronの学習記録です。今回はElectronのプロセスとその間での通信についてまとめます。

メインプロセスとレンダラープロセス

Electronの設計思想は「webアプリに似た仕組みでネイティブアプリを作れるようにする」です。そのため構成も2つのプロセスからなります。

webアプリはサーバが担当するバックエンドと、ブラウザが担当するフロントエンドの2つのプロセスで構成されています。この二つの間の通信はhttpなどの一般的な通信プロトコルで行われます。

Electronも内部的にはバックエンドに対応してNodeで実行するメインプロセスと、フロントエンドに対応してChromiumで動くレンダラープロセスに分かれています。これらの間の通信はIPC(Inter Process Connection)と呼ばれ、一般的なネットワークを通じたものではなく内部的な処理で通信が行われます。

ContextBridge

最新のIPC通信のための関数です。メインプロセスでpreload.jsを読ませてAPIを開き、レンダラープロセスとの通信はそのAPI経由でのみ行うようにするという方式です。

ElectronのIPC通信は様々な方式がありわかりにくいと思ったのですが、セキュリティ上の理由で更新が続けられており、これからはContextBridgeを使うのが主流になっていくようです。現在(v13.1.4)はContextBridge以外の方法はデフォルトオプションを変更しないと使えないようになっているので、新規にコードを起こすときはContextBridgeを使うようにするのがよいでしょう。

コード例

下記にアップロードしました。具体的には「フォームに推しの名前を書くとママと呼ぶ」という簡単なものです。

https://github.com/bluepost59/contextbridge_sample

ContextBridgeを使うにあたって主な変更点は下記です。まずpreload.jsというファイルを作成し、そこで開放するAPIを記述します。下記のように記述することで、myapiという名前空間にmamaというAPIが開放されます。

preload.js
const { contextBridge, ipcRenderer, ipcMain } = require('electron');

contextBridge.exposeInMainWorld('myapi', {
    mama: async (data) => await ipcRenderer.invoke('mama', data)
})

次に、メインプロセス内でBrowserWindowを作成するときに、webpreferenceオプションでpreload.jsをロードします。

index.js
const win = new BrowserWindow({
webPreferences: {
    preload: path.join(__dirname, 'preload.js'),
}
});

ここから関数を実装していきます。まずメインプロセスのコードにipcMainでAPIを実装します。

index.js
ipcMain.handle('mama', (event, data) => {
    return (`${data} mama`);
});

次にレンダラープロセス側で呼び出す処理を書きます。myapimamaというAPIが開放されているので、関数のように呼び出すことができます。

index.html
<script>
document.querySelector('#btn-mama').addEventListener(
    'click',
    async () => {
	const mama = document.querySelector('#mama');
	const buff = await window.myapi.mama(mama.value);
	alert(mama.value + "ママ!");
    });
</script>

参考

Discussion