| ページ一覧 | ブログ | twitter |  書式 | 書式(表) |

MyMemoWiki

「Electron」の版間の差分

提供: MyMemoWiki
ナビゲーションに移動 検索に移動
249行目: 249行目:
 
----
 
----
 
*[https://qiita.com/hibara/items/c59fb6924610fc22a9db IPCについて]
 
*[https://qiita.com/hibara/items/c59fb6924610fc22a9db IPCについて]
 +
*[https://qiita.com/pochman/items/64b34e9827866664d436 contextBridgeについて]
 
*メインプロセスとレンダラープロセスで情報を授受する場合、IPCを利用する
 
*メインプロセスとレンダラープロセスで情報を授受する場合、IPCを利用する
 
*ページAからページBを操作したい場合など、メッセージを ページA->メインプロセス->ページBと連携させる必要がある
 
*ページAからページBを操作したい場合など、メッセージを ページA->メインプロセス->ページBと連携させる必要がある

2021年10月1日 (金) 23:35時点における版

| Node.js | JavaScript | TypeScript | npm | Flutter |

目次

Electron

Fiddle


API Document


Required

基本的なアプリの作成


  • Electronアプリケーションは本質的にNode.jsアプリケーション
  • Electronアプリケーションは、package.json から開始される

プロジェクトの作成とElectronのインストール

mkdir my-electron-app && cd my-electron-app
npm init -y
npm i --save-dev electron
  • グローバルにインストール

npm

npm -g i electron

mainスクリプトファイル(main.js)の作成


  • mainスクリプトは、Electronアプリケーションのエントリーポイント
  • Mainプロセスを開始し、Mainプロセスはアプリケーションのライフサイクルをコントロールする
const { app, BrowserWindow } = require('electron')
const path = require('path')

function createWindow() {
    const win = new BrowserWindow({
        width:400,
        height:300,
        webPreferences:{
            preload: path.join(__dirname, 'preload.js')
        }
    })
    win.loadFile('index.html')
}

app.whenReady().then(() => {
    createWindow()

    app.on('activate', () =>{
        if (BrowserWindow.getAllWindows().length == 0) {
            createWindow()
        }
    })
})

app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
        app.quit()
    }
})

Webページ(index.html)の作成


  • index.html
  • アプリケーション初期化時に一度だけ表示されるページ
  • このページがレンダープロセスを表現する
<!DOCTYPE html>
<html>
<head>
    <meta carhset="UTF-8">
    <title>Electron Sample</title>
    <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
</head>
<body style="background: white;">
    <h2>Version</h2>
    <div>
        We are using Node.js <span id="node-version"></span>
    </div>
    <div>
        Chromium <span id="chrome-version"></span>,
    </div>
    <div>
        Electron <span id="electron-version"></span>.
    </div>
</body>
</html>

プレロードスクリプト(preload.js)


  • Node.jsとWebページのブリッジ
  • Node.js全体を安全に公開するのではなく、特定のAPIや動作をWebページに公開することができる
  • 以下ではprocessオブジェクトからバージョン情報を読み取りページを更新する
window.addEventListener('DOMContentLoaded', () => {
    const replaceText = (selector, text) => {
      const element = document.getElementById(selector);
      if (element) {
          element.innerText = text;
      }
    }
  
    for (const type of ['chrome', 'node', 'electron']) {
      replaceText(`${type}-version`, process.versions[type])
    }
  })

package.json


{
  "name": "electron_sample",
  "version": "1.0.0",
  "main": "main.js",
  "scripts": {
    "start": "electron .",
  },
      :
}

.gitignore


起動


npm start

Electron sample start.png

Visual Studio Codeでのデバッグ


launch.json Node を Visual Studio Code でデバッグするときにグローバルにインストールしたモジュールが読み込まれない

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Debug Main Process",
      "type": "node",
      "request": "launch",
      "cwd": "${workspaceFolder}",
      "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
      "windows": {
        "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
      },
      "args" : ["."],
      "outputCapture": "std"
    }
  ]
}

パッケージングと配布


Electron Forge


  • もっともシンプルで素早く配布するには、Electron Forgeを利用する
Electron ForgeをアプリケーションフォルダにImport
$ npm install --save-dev @electron-forge/cl
$ npx electron-forge import
✔ Checking your system
✔ Initializing Git Repository
✔ Writing modified package.json file
✔ Installing dependencies
✔ Writing modified package.json file
✔ Fixing .gitignore


We have ATTEMPTED to convert your app to be in a format that electron-forge understands.

Thanks for using "electron-forge"!!!
Mac 配布パッケージを作成

  • out フォルダに出力される
$ npm run make

> fx_sample@1.0.0 make
> electron-forge make

✔ Checking your system
✔ Resolving Forge Config
We need to package your application before we can make it
✔ Preparing to Package Application for arch: x64
✔ Preparing native dependencies
✔ Packaging Application
Making for the following targets: zip
✔ Making for target: zip - On platform: darwin - For arch: x64

Electron forge mac.png

Windows配布パッケージの作成


  • MacWindows用のパッケージ出力には、monoなどインストールが必要なようなので、Windows同様の手順でパッケージを作成。

Electron forge win.png

Ubuntu配布パッケージの作成


$ sudo apt install dpkg-dev
$ sudo apt install rpm
$ npm run make

Electron forge ubuntu.png

Electronの知識

プロセス


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


  • main.js がメインプロセスを担い、GUIは持たない
  • レンダーラープロセスは、Electronに内臓のWebブラウザを利用する
    • Electronの機能を利用する場合、、electron.remote経由
remoteオブジェクト

【Electron】remote moduleがdeprecatedになっている背景

  • レンダラープロセスから、appやBrowserWindowなどのメインプロセス専用の機能を利用したい場合に用意されている
  • remoteは内部にまるでメインプロセスのモジュールが用意されているかのように振る舞う
const { remote } = require('electron');

IPC(プロセス間通信)


  • IPCについて
  • contextBridgeについて
  • メインプロセスとレンダラープロセスで情報を授受する場合、IPCを利用する
  • ページAからページBを操作したい場合など、メッセージを ページA->メインプロセス->ページBと連携させる必要がある
ipcMain,ipcRenderer

Electron ipc.png

  • main.js Window生成
    • preload.js
    • contextIsolation: false
    let win = new BrowserWindow({
        width: 600,
        height: 400,
        webPreferences:{
            contextIsolation: false, // window object共有
            preload: path.join(__dirname, 'preload.js')
            // nodeIntegration: true,
            // enableRemoteModule: true
        }
    });
    // win.loadURL('https://service.typea.info/blogwiki');
    win.loadFile('index.html');
  • main.js 通信
const { ipcMain } = require('electron');
ipcMain.handle('invoke-test', (ev, msg) => {
    console.log("Message From Renderer:" + msg);
    return "Main response!"; 
});
  • preload.js
    • contextIsolation: false, // window object共有
const { ipcRenderer } = require('electron');
window.ipcRenderer = ipcRenderer;
  • index.html
    <script>
        ipcRenderer.invoke('invoke-test','sendmessage').then((data) => {
            console.log("Response from main:" + data);
        });
    </script>

オブジェクト

app


  • アプリケーション本体
  • 起動/終了、Windowオープン/クローズなどの管理

BrowserWindow


  • Electronアプリで表示されるウィンドウオブジェクト
  • HTMLファイルを読み込むことでウィンドウを表示する

WebContents


  • BrowserWindowに含まれ、Webコンテンツの状態管理
  • Webコンテンツに関するイベント

BrowserView


  • BrowserWindowでloadFile、、loadURLを使って表示するコンテンツに、さらにWebコンテンツを埋め込む
  • BrowserWindow内部に小さな内部Windowのようなものを追加し、別コンテンツを表示できる
    const view = new BrowserView();
    view.webContents .loadURL('https://service.typea.info/blogwiki');
    win.setBrowserView(view);
    view.setBounds({
        x : 100,
        y : 150,
        width : 300,
        height : 150
    });

Electron browser view.png

Menu


  • Menu,MenuItem
  • clickイベント
    let menu = new Menu();

    let menuFile = new MenuItem({
        label: 'ファイル',
        submenu: [
            { label: '新規2', click: () => { console.log('新規2'); } },
            new MenuItem({ label: '開く' }),
            new MenuItem({ label: '終了' }),
        ]
    });
    menu.append(menuFile);

    Menu.setApplicationMenu(menu);

Electron menu.png

テンプレートからメニューを作成する


  • セパレータは、type: 'separator'
    let menuFileTemplate = [
        {
            label: 'ファイル',
            submenu: [
                { label: '新規2', click: () => { console.log('新規2'); } },
                { label: '開く2' },
                { type: 'separator' },
                { label: '終了2' },
            ]
        }
    ];
    menu = Menu.buildFromTemplate(menuFileTemplate);
    Menu.setApplicationMenu(menu);

role


  • roleを指定するとロールの機能が組み込まれる
    • about
    • undo
    • redo
    • cut
    • copy
    • paste
    • pasteAndMatchStyle
    • selectAll
    • delete
    • minimize
    • close
    • quit
    • reload
    • forceReload
    • toggleDevTools
    • togglefullscreen
    • resetZoom
    • zoomIn
    • zoomOut
    • fileMenu
    • editMenu
    • viewMenu
    • windowMenu
        {
            label: '編集',
            submenu: [
                { label: '切り取り', role: 'cut' },
                { label: 'コピー', role: 'copy' },
                { label: '貼り付け', role: 'paste' },
            ]
        }

Electron menu role.png

構成

main.js


const { app, BrowserWindow} = require('electron');

function createWindow() {
    let win = new BrowserWindow({
        width: 400,
        height: 200,
        webPreferences:{
            contextIsolation: false, // window object共有
            preload: path.join(__dirname, 'preload.js')
            // nodeIntegration: true,
            // enableRemoteModule: true
        }
    });
    win.loadFile('index.html');
}

app.whenReady().then(createWindow);

オブジェクトの分割代入


const { app, BrowserWindow} = require('electron');

Preloadスクリプト


プリロードスクリプトには、ウェブコンテンツの読み込み開始前にレンダラープロセスで実行されるコードが含まれています。これらのスクリプトはレンダラーのコンテキスト内で実行されますが、Node.jsのAPIにアクセスできるため、より多くの権限が与えられています。

Node.js機能の統合


  • trueでNode.jsの機能(通常のWebで使用できないrequireなど)を利用できるようになる
nodeIntegration: true

remoteモジュールの有効化


  • remoteモジュールの有効化
enableRemoteModule: true

リモートコンテンツを読み込むレンダラー(BrowserWindow、BrowserView、<webview>)では、Node.jsの統合を有効にしないことが最も重要です。この目的は、リモートコンテンツに与える権限を制限することで、攻撃者がウェブサイト上でJavaScriptを実行できるようになった場合に、ユーザーに危害を加えることを劇的に難しくすることです。

この後、特定のホストに対して追加の権限を付与することができます。例えば、https://example.com/ に向けてBrowserWindowを開いている場合、そのWebサイトが必要とする能力を正確に与えることができますが、それ以上はできません。

Webページをロード


  • loadURLとすることで、外部ページをロードできる
   // win.loadFile('index.html');
   win.loadURL('https://service.typea.info/blogwiki');
 

Electron web app.png

モーダルダイアログ


function createWindow() {
    let win = new BrowserWindow({
        width: 600,
        height: 400,
        webPreference: {
            nodeIntegration: true,
            enableRemoteModule
        }
    });
    // win.loadURL('https://service.typea.info/blogwiki');
    win.loadFile('index.html');

    let child = new BrowserWindow({
        width: 400,
        height: 200,
        parent: win,
        frame: false,
        modal: true,
        transparent: true,
        opacity: 0.5
    });
    child.loadFile('dialog.html');
}

Electron modal dialog.png

デベロッパーツールを開く


win.webContents.openDevTools();

Electron devtools.png

appオブジェクトのイベント

起動処理の完了

will-finish-launching

初期化処理完了

ready

BrowserWindowの生成

browser-window-created

Webコンテンツの生成

web-contents-created

全てのWindowが閉じられた

window-all-closed

全てのWindowを閉じる前

before-quit

終了する前

will-quit

終了時

quit

BrowserWindowのイベント

Windowの表示

show

Windowの非表示

hide

Window表示準備完了

ready-to-show

Windowを閉じる

close

Windowが閉じられた

closed

その他

  • focus
  • blur
  • maximize
  • unmaximize
  • minimize
  • restore
  • will-resize
  • resize
  • will-move
  • move
  • enter-full-screen
  • leave-full-screen
  • enter-html-full-screen
  • leave-html-full-screen
  • always-on-top-changed

BrowseWindow操作

  • destory
  • close()
  • focus()
  • blur()
  • isFocuced()
  • isDestoryed()
  • show()
  • showInactive()
  • hide()
  • isVisible()
  • isModal()
  • maximize()
  • unmaximize()
  • isMaximized()
  • minimize()
  • restore
  • isMinimized()
  • setFullScreen()
  • isFullScreen()
  • isNormal()
  • SetBounds()
  • GetBounds()
  • SetContentBounds()
  • GetContentsBound()
  • SetSize()
  • GetSize()
  • SetContaentSize()
  • GetContentSize()
  • SetMinimumSize()
  • GetMinimumSize
  • SetMaximumSize()
  • GetMaximumSize()
  • SetPosition()
  • GetPosition()
  • moveTop()
  • center()
  • settitle()
  • getTitle()

WebContentsのイベント

コンテンツロード完了

did-finish-load

フレームのコンテンツロード

did-frame-finish-load

コンテンツ読み込み開始

did-start-loading

コンテンツ読み込み中止

did-stop-loading

DOM生成完了

dom-ready

新しいWindow作成

new-window

URLアクセス時

will-navigate

URLアクセス開始

did-start-navigation

その他

  • will-redirect
  • did-redirect-navigation
  • did-navigate
  • will-prevent-unload
  • destroyed
  • enter-html-full-screen
  • leave-html-full-screen
  • zoom-changed
  • devtools-opend
  • devtools-closed
  • devtools-focused
  • console-message