Help us understand the problem. What is going on with this article?

[Electron] macOS の 'Open with...'(このアプリケーションで開く)がつらい

はじめに

スタート地点

もっともシンプルなメインプロセスのコードは以下のようになると思います。
(TypeScriptで記述していますがJSでも大差ないので無視してください)

src/main.ts
import { app, BrowserWindow } from 'electron';

let win: BrowserWindow | null = null;

app.on('ready', () => {
  win = new BrowserWindow({ webPreferences: { nodeIntegration: true } });
  win.loadFile('dist/index.html');
  win.on('closed', () => {
    win = null;
  });
});

app.on('window-all-closed', () => app.quit());

つらい

readyイベントではアプリ起動時のファイルパスを受け取れない

公式にも書いてある通りです。

src/main.ts
let filepath: string | null = null;

// 'ready'イベントより前に発火するイベントを使う
app.on('will-finish-launching', () => {
  app.on('open-file', (e, path) => {
    // 必須
    e.preventDefault();
    // readyイベント前(BrowserWindowインスタンスの作成前)のため
    // いったん変数に預ける
    filepath = path;
  });
});

app.on('ready', () => {
  // 略

  // filepath変数の回収
  win.webContents.on('did-finish-load', () => {
    if (win && filepath) {
      // レンダラープロセスに送る
      win.webContents.send('selected-file', filepath);
      // 変数の初期化
      filepath = null;
    }
  });

  // 略
});

// アプリ起動後の'open-file'イベントの処理
app.on('open-file', (e, path) => {
  e.preventDefault();
  if (win) win.webContents.send('selected-file', path);
});

アプリ起動後の場合、条件によってはsecond-instanceが起動してそのファイルを開くことがある

  • Dockに登録したアイコンからアプリ起動 -> Finderで「このアプリケーションで開く」など

かならず既に起動しているウィンドウで開くことを期待するのであれば、やはりシングルインスタンスを強制するしかありません。

src/main.ts
const gotTheLock = app.requestSingleInstanceLock();

if (gotTheLock) {
  app.quit();
} else {
  app.on('second-instance', () => {
    if (win) {
      if (win.isMinimized()) win.restore();
      win.focus();
    }
  });

  app.on('will-finish-launching', () => {
    // 略
  });

  app.on('ready', () => {
    // 略
  });

  app.on('open-file', (e, path) => {
    // 略
  });
}

app.on('window-all-closed', () => app.quit());

info.plist に扱うファイルを登録しておかないと、そもそも右クリックメニューにエントリされない && 推奨するアプリとして扱ってくれない

ここではelectron-packagerでのパッケージング方法を記述します。
electron-builderでも同等のことが出来ます。

また、各種識別子を設定することで前項「second-instanceが〜」の抑止にもなります。

bash
$ electron-packager . AppName --extend-info=extend.plist
extend.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>CFBundleDisplayName</key>
    <string>AppName</string>
    <key>CFBundleExecutable</key>
    <string>AppName</string>
    <key>CFBundleIdentifier</key>
    <string>com.electron.appname</string>
    <key>CFBundlePackageType</key>
    <string>APPL</string>
    <key>CFBundleDocumentTypes</key>
    <array>
      <dict>
        <key>CFBundleTypeName</key>
        <string>ImageFile</string>
        <key>CFBundleTypeRole</key>
        <string>Viewer</string>
        <key>LSItemContentTypes</key>
        <array>
          <string>com.microsoft.bmp</string>
          <string>public.jpeg</string>
          <string>public.png</string>
        </array>
      </dict>
    </array>
  </dict>
</plist>
  • CFBundleDisplayName (必須) Appバンドルの表示名
  • CFBundleExecutable (推奨) 実行ファイルの識別子
  • CFBundleIdentifier (推奨) Appバンドルの識別子
  • CFBundlePackageType バンドルの種類、アプリの場合はAPPL
  • CFBundleDocumentTypes アプリがサポートするファイルの種類を定義
  • CFBundleTypeName (必須) ドキュメントタイプの抽象名
  • CFBundleTypeRole (必須) アプリの役割 Viewer, Editor, Shell or None
  • LSItemContentTypes 対応するファイルのUTI(統一型識別子)
  • CFBundleTypeExtensionsはDuplicated

※ UTIの一覧はこちら (Apple)

参照リンク

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした