メインコンテンツへ飛ぶ

ディープリンク

概要

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

このチュートリアルを終える頃には、特定のプロトコルで始まる 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 = () => {
// ブラウザウィンドウを作成します。
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})

mainWindow.loadFile('index.html')
}

この次のステップで、BrowserWindow を作成し、外部プロトコルがクリックされたイベントの処理方法をアプリケーションに伝えます。

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

Windows と Linux のコード:

const gotTheLock = app.requestSingleInstanceLock()

if (!gotTheLock) {
app.quit()
} else {
app.on('second-instance', (event, commandLine, workingDirectory) => {
// 誰かが 2 つ目のインスタンスを実行しようとしたので、ウインドウにフォーカスさせなければなりません。
if (mainWindow) {
if (mainWindow.isMinimized()) mainWindow.restore()
mainWindow.focus()
}
// commandLine は文字列の配列で、最後の要素がディープリンクの URL です。
dialog.showErrorBox('Welcome Back', `You arrived from: ${commandLine.pop()}`)
})

// mainWindow を作成する、アプリの残りも読み込む、etc...
app.whenReady().then(() => {
createWindow()
})
}

macOS のコード:

// このメソッドは、Electron の初期化が完了し、
// ブラウザウインドウの作成準備ができると呼び出されます。
// 一部のAPIはこのイベントが発生した後にのみ利用できます。
app.whenReady().then(() => {
createWindow()
})

// プロトコルのハンドリング。 今回は、エラーボックスを表示することにします。
app.on('open-url', (event, url) => {
dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`)
})

最後に、誰かがアプリケーションを閉じたときの処理コードを追加します。

// macOS 以外では、すべてのウインドウを閉じたときに終了します。 // ユーザが Cmd + Q で明示的に終了するまで、アプリケーションと
// そのメニューバーがアクティブになっているのが一般的です。
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})

重要な注意事項

パッケージ化

macOS と Linux では、この機能はアプリがパッケージ化されているときのみ動作します。 開発中でコマンドラインから起動した場合は動作しません。 アプリをパッケージ化する際には、アプリの macOS の Info.plist と Linux の .desktop が更新され、その新しいプロトコルハンドラが含まれていることを確認するようにしてください。 Electron のアプリのバンドル及び頒布ツールには、この処理を行ってくれるものもあります。

Electron Forge

If you're using Electron Forge, adjust packagerConfig for macOS support, and the configuration for the appropriate Linux makers for Linux support, in your Forge configuration (please note the following example only shows the bare minimum needed to add the configuration changes):

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

Electron パッケージャ

macOS サポートの場合:

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

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

packager({
// ...他のオプション...
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)
})