Electron.jsにてプロセス間通信を汎用的に実装したい
Electronを使用してデスクトップアプリを開発している中で、メインプロセスとレンダラープロセス間での通信処理を汎用的(使い回しできるよう)にしたいなということで、アイデアを紹介します。
本記事は、メモ書きのようなもので、SEOは特に考慮していません。
また、熟練者のようなコードではありませんので、あくまで参考になればと思って書いています。
サンプルソース
プリロードファイル(preload.ts)
import { contextBridge, ipcRenderer, IpcRendererEvent } from "electron"
contextBridge.exposeInMainWorld("myAPI", {
// renderer -> main
send: (
channel: string,
...args: any[]
) => ipcRenderer.send(channel, args),
// main -> renderer
on: (
channel: string,
callback: (event: IpcRendererEvent, ...args: any[]) => any
) => ipcRenderer.on(channel, (event, args) => callback(event, args)),
})
プリロードファイルが一番重要かと思い、最初に記述しました。
メインとレンダラーのプロセス間送受信を実現しています。
メインファイルの送受信処理
// レンダラーに送信
mainWindow.webContents.send("channel:a", args)
// レンダラーから受信(リスナー)
ipcMain.on("channel:b", (args) => {
// 好きな処理
})
// リスナーの削除(一応書いときます)
ipcMain.removeAllListeners("channel:b")
レンダラーファイルの送受信処理
// メインから受信
window.myAPI.on("channel:a", (_event, args) => {
// 好きな処理
})
// メインに送信
window.myAPI.send("channel:b", args)
メインファイル、レンダラーファイル共に「args」の部分は好きなように設定してください。
レンダラーの処理は、windowオブジェクトが生成されていないとエラーになるので、私はuseEffect内に記述するようにしましたが、この方法が正しいのか不安です…動くからいっか
インターフェースファイル(any多くてすみません)
declare global {
interface Window {
myAPI: IMyAPI
}
}
export interface IMyAPI {
send: (channel: string, ...args: any[]) => any
on: (
channel: string,
callback: (event: IpcRendererEvent, ...args: any[]) => any
) => any
}
さいごに
すごく簡略した記述で、申し訳ないです…
Electron公式のドキュメントと見比べながら実装してみてください。
アドバイスとかあればくださいm(_ _)m