跳至主要內容

深度連結

概觀

本指南將帶您了解將您的 Electron 應用程式設定為特定協定的預設處理程式的過程。

在本教學結束時,我們將設定我們的應用程式來攔截和處理任何以特定協定開頭的點擊網址。在本指南中,我們將使用的協定是「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 中會有所不同。這是因為這兩個平台都發出 second-instance 事件,而不是 open-url 事件,並且 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,請調整 macOS 支援的 packagerConfig 和 Linux 支援的適當 Linux makers 的設定,在您的Forge 設定中 (請注意,以下範例僅顯示新增設定變更所需的最低限度)

{
"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 的處理方式類似,只是 protocols 是傳遞至 packager 函式的 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)
})