跳到主要内容

深度链接

概述

本指南将引导您完成将您的 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 中会有所不同。这是因为这两个平台都发出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)
})