Electron を Custom URL Scheme で起動する


やりたいこと

Custom URL Scheme から Electron を起動したい、値も渡したい

例えばブラウザで、 itmss://music.apple.com/jp/album/i-g-y/617827654?i=617827657 にアクセスすると iTunes が起動し、特定のページに遷移する

これと同じことを実現したい

前提

  • Electron version v5.0
  • electron-builder v20.40.2

手順

Mac

package.json の build に以下を追記する

"build": {
    ...
    "protocols": {
      "name": "myApp IM URL",
      "schemes": [
        "my-appname"
      ]
    },
   ...
}

ビルド後に .dmg イメージからアプリケーションを Mac にインストールすることで、 URL Scheme から Electron を起動することができる

Windows

package.json の build に以下を追記する

"build": {
    ...
    "nsis": {
      "include": "build/installer.nsh",
      "perMachine": true
    },
   ...
}

build/installer.nsh ファイルを追加する

!macro customHeader
    !system "echo '' > ${BUILD_RESOURCES_DIR}/customHeader"
!macroend

!macro preInit
    ; This macro is inserted at the beginning of the NSIS .OnInit callback
    !system "echo '' > ${BUILD_RESOURCES_DIR}/preInit"
!macroend

!macro customInit
    !system "echo '' > ${BUILD_RESOURCES_DIR}/customInit"
!macroend

!macro customInstall
    !system "echo '' > ${BUILD_RESOURCES_DIR}/customInstall"

    DetailPrint "Register My AppName URI Handler"
    DeleteRegKey HKCR "My AppName"
    WriteRegStr HKCR "My AppName" "" "URL:my-appname"
    WriteRegStr HKCR "My AppName" "URL Protocol" ""
    WriteRegStr HKCR "My AppName" "EveHQ NG SSO authentication Protocol" ""
    WriteRegStr HKCR "My AppName\DefaultIcon" "" "$INSTDIR\${APP_EXECUTABLE_FILENAME}"
    WriteRegStr HKCR "My AppName\shell" "" ""
    WriteRegStr HKCR "My AppName\shell\Open" "" ""
    WriteRegStr HKCR "My AppName\shell\Open\command" "" "$INSTDIR\${APP_EXECUTABLE_FILENAME} %1"
!macroend

!macro customInstallMode
    # set $isForceMachineInstall or $isForceCurrentInstall
    # to enforce one or the other modes.
!macroend

ビルド後、 Setup ファイルからインストールすることで、 URL Scheme から Electron を起動することができる

Custom URI Scheme を Electron 側で取得する

メインプロセス

Mac OS と Windows で書き方が違う

  // for Mac OS
  app.on('open-url', (e, url) => {
    // URL Scheme から開いたときにここが実行される
    webContents.send('customUri', url);
  });

  // アプリの二重起動を防ぐ(for windows)
  const gotTheLock = app.requestSingleInstanceLock();
  if (!gotTheLock) { // すでにウィンドウを開いていた場合、新しい window は quit
    app.quit();
  } else {
    // 2つめのウィンドウが開かれた時のイベントを定義する
    app.on('second-instance', (event, commandLine, workingDirectory) => {
      // mainWindow.webContents.send('log', 'second instance!!');

      commandLine.forEach(cmd => {
        // URIスキームのみを探して、レンダラプロセスに送る
        if (/my-appname:\/\//.test(cmd)) {
          mainWindow.webContents.send('customUri', cmd);
        }
      });

      // すでにメインウィンドウがある場合、それにフォーカスする
      if (mainWindow) {
        if (mainWindow.isMinimized()) { // 最小化してた場合
          mainWindow.restore(); // restore
        }
        mainWindow.focus(); // フォーカス
      }
    });
  }

レンダラプロセス

/**
 * custom uri をメインプロセスから受け取る
 */
ipcRenderer.on('customUri', (event, uri) => {
  console.log('customUri:', uri);
});

参考