Open7

Electronのメインプロセスとレンダラープロセスの間のプロセス間通信について

ahoxa1rxahoxa1rx

例示のコードはElectronの公式ドキュメントから参照

  • やりたいこと
    • ボタンアクションでファイル操作などが行いたい
    • メニューバーからでもついでにできたら
ahoxa1rxahoxa1rx

Electronでは表示部分のレンダラープロセス,アプリの構築やアプリ内での様々な操作に関してはメインプロセスに分けられており,レンダラーでのイベントをもとに様々な高度な操作を行いたい場合,メインプロセスへデータを渡してメインプロセス内で実行した結果をレンダラープロセスに再び渡すことで結果を反映させることができる.
キーワード: ipcMain, ipcRenderer, contextBridge

ahoxa1rxahoxa1rx

表示画面のボタンを押すとファイル選択画面が開き,選択したファイル名を表示するプログラムの作成
これはレンダラー→メイン→レンダラーのような通信

ahoxa1rxahoxa1rx
renderer.js
const btn = document.getElementById('btn')

btn.addEventListner('click', async () => {
  const filePath = await window.openFile()
}

contextBridgeによってメインプロセスとレンダラープロセス間のAPI等を定義する.

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

contextBridge.exposeInMainWorld('electronAPI',{
  openFile: () => ipcRenderer.invoke('dialog:openFile')
})

'electronAPI'としているのは不明,ドキュメントでは'electron'としている. 渡された文字列がレンダラーで呼び出す際のAPIキーになる……?

  • contextBridge.exposeInMainWorld(apiKey, api)
    • apiKey: string
    • api: any --- anyだがAPIの定義をここに記述する.
ahoxa1rxahoxa1rx
main.js
const {app, BrowserWindow, ipcMain, dialog} = require('electron')
const path = require('path')

async function handleFileOpen() {
  const { canceled, filePaths } = await dialog.showOpenDialog()
  if (canceled) {
    return
  } else {
    return filePaths[0]
  }
}

function createWindow () {
//...
}

app.whenReady().then(() => {
  ipcMain.handle('dialog:openFile', handleFileOpen)
  createWindow()
  app.on('activate', function () {
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
})

//...
  • dialog.showOpenDialog():Promise<Object> ファイルを開く際のダイアログボックスを呼び出す.
    • returns Promise<Obhect>
      • canceled:boolean ダイアログでキャンセルをされたかどうか
      • filePaths:string[] 選択したファイルのパス(複数可)
    • ipcMain.handle(channel: string, listner: Function<Promise<void> | any>)
      • ipcRenderer.invoke(channel, ...args)がレンダラープロセスにおいて呼び出された際に呼び出すハンドラをメインプロセスに追加する.
ahoxa1rxahoxa1rx

ひとまずまとめ:

  • 描画以外の操作(ファイル操作等)を行うのはメインプロセス
  • レンダラープロセスから描画以外の操作を呼び出すために,プロセス間通信を行う.
    • メインプロセスとレンダラープロセス間を結ぶのがAPI
      • これはcontextBridge.exposeInMainWorld()で定義する
    • レンダラープロセス側はipcRenderer.invoke()
    • メインプロセス側はipcMain.handle()
ahoxa1rxahoxa1rx

ここからメニューバーからファイル選択のダイアログ等を呼び出し,ファイル名を描画する際の流れ