本文へ移動

Deep Links

概要

このガイドでは、特定のプロトコルのデフォルトハンドラーとしてElectronアプリを設定する手順を説明します。

このチュートリアルの最後には、特定のプロトコルで始まるクリックされたURLをインターセプトして処理するようにアプリを設定します。このガイドでは、「electron-fiddle://」というプロトコルを使用します。

メインプロセス (main.js)

まず、electronから必要なモジュールをインポートします。これらのモジュールは、アプリケーションのライフサイクルの制御とネイティブブラウザウィンドウの作成に役立ちます。

const { app, BrowserWindow, shell } = require('electron')
const path = require('node:path')

次に、すべての「electron-fiddle://」プロトコルを処理するようにアプリケーションを登録します。

if (process.defaultApp) {
if (process.argv.length >= 2) {
app.setAsDefaultProtocolClient('electron-fiddle', process.execPath, [path.resolve(process.argv[1])])
}
} else {
app.setAsDefaultProtocolClient('electron-fiddle')
}

ここで、ブラウザウィンドウを作成し、アプリケーションのindex.htmlファイルをロードする関数を定義します。

let mainWindow

const createWindow = () => {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})

mainWindow.loadFile('index.html')
}

次のステップでは、BrowserWindowを作成し、外部プロトコルがクリックされたイベントをアプリケーションがどのように処理するかを指定します。

このコードは、macOSとWindowsおよびLinuxでは異なります。これは、両方のプラットフォームがopen-urlイベントではなくsecond-instanceイベントを発行し、Windowsではプロトコルリンクの内容を同じElectronインスタンス内で開くために追加のコードが必要であるためです。詳細についてはこちらをご覧ください。

WindowsとLinuxのコード:

const gotTheLock = app.requestSingleInstanceLock()

if (!gotTheLock) {
app.quit()
} else {
app.on('second-instance', (event, commandLine, workingDirectory) => {
// Someone tried to run a second instance, we should focus our window.
if (mainWindow) {
if (mainWindow.isMinimized()) mainWindow.restore()
mainWindow.focus()
}
// the commandLine is array of strings in which last element is deep link url
dialog.showErrorBox('Welcome Back', `You arrived from: ${commandLine.pop()}`)
})

// Create mainWindow, load the rest of the app, etc...
app.whenReady().then(() => {
createWindow()
})
}

macOSのコード:

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
createWindow()
})

// Handle the protocol. In this case, we choose to show an Error Box.
app.on('open-url', (event, url) => {
dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`)
})

最後に、アプリケーションの終了時に処理するための追加のコードを追加します。

// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})

重要な注意事項

パッケージ化

macOSとLinuxでは、この機能はアプリがパッケージ化されている場合にのみ機能します。コマンドラインから開発環境で起動した場合は機能しません。アプリをパッケージ化する場合、アプリのmacOSのInfo.plistファイルとLinuxの.desktopファイルに新しいプロトコルハンドラーを含めるように更新する必要があります。アプリのバンドルと配布を行うElectronツールの一部では、この処理が自動的に行われます。

Electron Forge

Electron Forgeを使用している場合は、Forgeの設定でmacOSのサポートのためにpackagerConfigを、Linuxのサポートのために適切なLinuxメーカーの設定を調整してください(次の例は、設定変更に必要な最小限の項目のみを示しています)。

{
"config": {
"forge": {
"packagerConfig": {
"protocols": [
{
"name": "Electron Fiddle",
"schemes": ["electron-fiddle"]
}
]
},
"makers": [
{
"name": "@electron-forge/maker-deb",
"config": {
"mimeType": ["x-scheme-handler/electron-fiddle"]
}
}
]
}
}
}

Electron Packager

macOSサポートの場合

Electron PackagerのAPIを使用している場合、プロトコルハンドラーのサポートの追加方法はElectron Forgeの処理方法と似ていますが、protocolspackager関数に渡されるPackagerオプションの一部です。

const packager = require('@electron/packager')

packager({
// ...other options...
protocols: [
{
name: 'Electron Fiddle',
schemes: ['electron-fiddle']
}
]

}).then(paths => console.log(`SUCCESS: Created ${paths.join(', ')}`))
.catch(err => console.error(`ERROR: ${err.message}`))

Electron PackagerのCLIを使用している場合は、--protocolフラグと--protocol-nameフラグを使用します。例:

npx electron-packager . --protocol=electron-fiddle --protocol-name="Electron Fiddle"

結論

Electronアプリを起動した後、カスタムプロトコルを含むURL(例:「electron-fiddle://open」)をブラウザに入力し、アプリケーションが応答してエラーダイアログボックスを表示することを確認できます。

// Modules to control application life and create native browser window
const { app, BrowserWindow, ipcMain, shell, dialog } = require('electron/main')
const path = require('node:path')

let mainWindow

if (process.defaultApp) {
if (process.argv.length >= 2) {
app.setAsDefaultProtocolClient('electron-fiddle', process.execPath, [path.resolve(process.argv[1])])
}
} else {
app.setAsDefaultProtocolClient('electron-fiddle')
}

const gotTheLock = app.requestSingleInstanceLock()

if (!gotTheLock) {
app.quit()
} else {
app.on('second-instance', (event, commandLine, workingDirectory) => {
// Someone tried to run a second instance, we should focus our window.
if (mainWindow) {
if (mainWindow.isMinimized()) mainWindow.restore()
mainWindow.focus()
}

dialog.showErrorBox('Welcome Back', `You arrived from: ${commandLine.pop().slice(0, -1)}`)
})

// Create mainWindow, load the rest of the app, etc...
app.whenReady().then(() => {
createWindow()
})

app.on('open-url', (event, url) => {
dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`)
})
}

function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})

mainWindow.loadFile('index.html')
}

// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})

// Handle window controls via IPC
ipcMain.on('shell:open', () => {
const pageDirectory = __dirname.replace('app.asar', 'app.asar.unpacked')
const pagePath = path.join('file://', pageDirectory, 'index.html')
shell.openExternal(pagePath)
})