Electron を使って Windows タスクトレイ・Mac メニューバーに常駐するアプリを作る

以前少しイジったきりの Electron を使って、Windows のタスクトレイや、Mac のメニューバーに常駐するアプリを作ってみる。

目次

ソースコード

先に、今回実装したソースコードの全量を紹介する。以下の GitHub リポジトリより確認いただける。

作業ディレクトリを準備する

適当な作業ディレクトリを作り、Electron と、各プラットフォーム向けにビルドしてくれる Electron-Builder をインストールする。

$ npm init -y
$ npm install -D electron electron-builder

package.json を編集する

Electron-Builder の設定は package.json に書けるので、package.json を直していく。適宜コメントを入れているが、実際はコメント行があると不正な JSON ファイルになってしまうので、コメントは削除すること。

{
  "name": "practice-electron-tray-app",
  // バージョン番号がビルド時に必要になる
  "version": "0.0.0",
  "description": "Practice Electron Tray App",
  "private": true,
  // エントリポイントのファイルを指定する。この記述がないと main.js を自動的に探してくれる
  "main": "index.js",
  "scripts": {
    // 開発用のビルド
    "start": "electron ./",
    // 資材が出力されるディレクトリを空にする。適宜 rimraf など使うと良い
    "clear": "rm -rf ./dist",
    // Windows と Mac 向け両方にビルドする
    "build": "electron-builder -mw",
    // Windows 向けにビルドする
    "build": "electron-builder -w",
    // Mac 向けにビルドする
    "build": "electron-builder -m"
  },
  // Author 情報がビルド時に必要になる
  "author": "Neo <neos21@gmail.com> (https://neos21.net/)",
  "license": "MIT",
  "devDependencies": {
    "electron": "11.0.3",
    "electron-builder": "22.9.1"
  },
  // 以下、ビルド用の設定
  "build": {
    "productName": "Practice Electron Tray App",
    "appId": "com.example.practice.electron.tray.app",
    "mac": {
      "target": "dir"
    },
    "win": {
      "target": "dir"
    }
  }
}

タスクトレイ用の .ico、メニューバー用の .png ファイルを用意する

Windows のタスクトレイに表示できるアイコンファイルは .ico 形式で用意する。

一方、メニューバー用のアイコンファイルは .png 形式で用意する。

いずれも 16×16px で用意しておけばとりあえず動く。ココでは icon-16.icoicon-16.png というファイル名で用意したことにする。

どうも icon.png などのファイル名でファイルを置いておくと、アプリアイコン用のアセットファイルと勘違いされてビルド時にエラーになるので、単純な icon というファイル名だけ避けておく。

index.js を実装する

package.jsonmain プロパティで指定した、エントリポイントとなる index.js を実装する。

const electron = require('electron');

let tray = null;  // GC でトレイアイコンが消えないようにする

electron.app.on('ready', () => {
  // Mac のみ Dock は非表示にする
  if(process.platform === 'darwin') electron.app.dock.hide();
  
  // ビルド後にパスが狂わないよう `__dirname` を使う
  tray = new electron.Tray(`${__dirname}/icon-16.${process.platform === 'win32' ? 'ico' : 'png'}`);
  tray.setContextMenu(electron.Menu.buildFromTemplate([
    {
      label: 'Hello World',
      click: () => {
        electron.dialog.showMessageBoxSync({
          title: 'Neo\'s Electron Tray App',
          message: 'Hello World',
          detail: `This Is Neo's Electron Tray App. [${process.platform}]`
        });
      }
    },
    {
      type: 'separator'
    },
    {
      label: 'Exit',
      role: 'quit'
    }
  ]));
});

今回はアイコンを右クリックするとちょっとしたメニューが出てきて、選択するとアラートダイアログが表示されるだけの簡単なコードだ。

Electron は process.platform で OS を判断して条件分岐する箇所が多い。今回のような最小構成でも、Dock アイコンを非表示にする時と、トレイアイコンのファイルを指定する時に使用している。

ビルドしてみる

とりあえず手元で動かしてみるだけなら、$ npm start で試せる。

Windows・Mac 向けの両方の形式でビルドするなら、$ npm run build を実行する。実行環境が Windows でも Mac でも問題ない。.exe.app ファイルがちゃんと出来上がる。

ビルドした .exe.app を実行すれば、タスクトレイやメニューバーにアイコンが追加され、動作していることが分かるだろう。

以上

Electron を使って、比較的簡単にマルチプラットフォーム対応なネイティブアプリが作れた。

OS 判定が点在しそうなので、いかに整理されたコードが書けるかがポイントになりそうだ。