1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Electron:ver12のcontextBridgeとipcRenderer.invoke

Last updated at Posted at 2021-04-16

 本記事では、ElectronのVer.12以降でセキュアにモジュールを使用する際に躓きがちな「ContextBridge.ipcMainWorld」と「ipcRenderer.invoke」について解説します!
 さらに、具体例にSlackAPIによるメッセージの送信を使用することで、一緒に使い方を覚えてしまおうという魂胆です!

(注意)
 非プログラマーの独学&初投稿になりますのでどうぞお手柔らかに。
 ここ直すといいよ!というアドバイスいただけたら幸いです!

##目次

  1. 作成する機能
  2. セキュアにモジュールを使用するには
  3. 実際にやってみる
  4. SlackAPIでメッセージ送信
  5. まとめ

1.作成する機能

 「ボタンをクリックしたら、Slackにあらかじめ決められたメッセージ(かめはめ波)を飛ばす」だけの非常にシンプルな機能を作成します。
 という建前のもと、デバックの取り方わからなかったので、代わりにAPIでメッセージを投げます(笑)

electronについてはこちら

2.セキュアにモジュールを使用するには

electronでは、以前からXSSの危険性が指摘されています。
バージョン更新のたびにデフォルトの設定が変更になるなど、
私を含め初心者にとってややこしい状況かと。

まずは公式ドキュメントを見てみましょう。また併せて日本語でも検索します。
それぞれ共通するキーワードをピックアップします。

  • preload.js
  • ContextBridge.ipcMainWorld
  • ipcRenderer.invoke
  • ipcMain.handle

これらを組み合わせることにより、従来より指摘されていたXSSの危険性を回避しつつ、モジュールを使用することができるっぽいですね。

全体のイメージはこんな感じでしょうか。
無題の図形描画.jpg

3.実際にやってみる

まずはじめに、画面となるHTMLを準備します。

test.html
<html lang="ja">

<head>
  <meta charset="UTF-8">
  <meta content="width=device-width" name="viewport">
  <title>テスト</title>
</head>

<body>
  <p><input type="button" value="かめはめ波" id=Button></p>
  <script src="./renderer.js"></script>
</body>

</html>

 rendererプロセス側から「window.任意のAPIキー.任意のAPI名(引数)」という形でpreload.jsの処理を呼び出します。

renderer.js
const button = document.getElementById("Button");
button.addEventListener('click',async () => {
    const result = await window.electron.sendToMain("かめはめ波");
    console.log(result);
  }) 

 次にpreload.jsでは、「contextBridge.exposeInMainWorld('任意のAPIキー', {任意のAPI名:処理内容})」という形で窓口を用意します。
 この時、処理内容には「ipcRenderer.invoke('任意の名前', 引数)」を記述し、mainプロセスの処理を呼びに行きます。

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

contextBridge.exposeInMainWorld(
    'electron', {
        sendToMain: async (skill) => { 
            const result = await ipcRenderer.invoke('invoke-test', skill) ;
            return result;
        }
})

 最後にmainプロセスでは、preload.jsに対応する「ipcMain.handle('任意の名前',async(event,data) => { 処理内容...}」と記述し、呼び出しの受け取りと処理の実行を行います。

main.js
ipcMain.handle('invoke-test', async(event,data) => {
  const Result = await sendMessageSlack();
  return Result
});

const sendMessageSlack = async() => {
  //処理
}

SlackAPIでメッセージ送信

SlackのApiの使用に関してはこちら

 上記のMainプロセスで呼び出される関数を以下のように記述します。TokenやChannel名は態々外に出さなくてもいいかもですが、後から見てわかりやすいかなと思ってconstしてます。

main.js
const { WebClient, LogLevel } = require("@slack/web-api");
const apiToken = "Slackの設定で取得したApiToken";
const chatGroup = "任意のチャンネル名";
const client = new WebClient(apiToken, {logLevel: LogLevel.DEBUG});

const sendMessageSlack = async(text) => {
  try {
    const result = await client.chat.postMessage({
      token: apiToken,
      channel: chatGroup,
      text: text
    });
    console.log(result);
  }
  catch (error) {
    console.error(err);
  }
}

まとめ

その他の参考記事

所感
 初心者にとって、async/awaitが入れ子になっている上に、他では使わない概念の理解やMethodの使用が求められ、なかなか大変でした。
 すでに同様の内容を書かれている記事も見ましたが、うまく動かなかったり、
かゆいところに届かなかったりで、自分で試行錯誤して何とかたどり着きました。
 もし同じような境遇の方がこれをタタキにして、やりたかったことができると👍

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?