Skip to content

深度链接 (Deep Links)

示例

主进程 (main.js)

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 有所不同。 这是因为这两个平台会触发 second-instance 事件,而不是 open-url 事件,而且 Windows 需要额外的代码才能在同一个 Electron 实例中打开协议链接的内容。

Windows 和 Linux 的代码示例

const gotTheLock = app.requestSingleInstanceLock()

if (!gotTheLock) {
    app.quit()
} else {
    app.on('second-instance', (event, commandLine, workingDirectory) => {
        // 用户正在尝试运行第二个实例,我们需要让焦点指向我们的窗口
        if (mainWindow) {
        if (mainWindow.isMinimized()) mainWindow.restore()
        mainWindow.focus()
        }
        // 命令行是一个字符串数组,其中最后一个元素是深度链接的URL。
        dialog.showErrorBox('Welcome Back', `You arrived from: ${commandLine.pop()}`)
    })

    // 创建主窗口,加载应用程序的其他部分,等等...
    app.whenReady().then(() => {
        createWindow()
    })
}

MacOS 代码示例

// Electron 在完成初始化,并准备创建浏览器窗口时,
// 会调用这个方法。
// 部分 API 在 ready 事件触发后才能使用。
app.whenReady().then(() => {
    createWindow()
})

// 处理协议 在本例中,我们选择显示一个错误提示对话框。
app.on('open-url', (event, url) => {
    dialog.showErrorBox('欢迎回来', `导向自: ${url}`)
})
最后,我们还需要处理应用的关闭事件。
// 在除 MacOS 的其他平台上,当所有窗口关闭后,退出当前应用。 在 MacOS 上,
// 应用及其菜单栏通常会保持活跃状态,
// 直到用户明确按下 Cmd + Q 退出应用
app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') app.quit()
})

重要提醒

打包

在 macOS 和 Linux 上,此功能仅在应用打包后才有效。 在命令行启动的开发版中无效。 当您打包应用程序时,你需要确保应用程序的 macOS Info.plist 和 Linux .desktop 文件已更新以包含新的协议处理程序。 一些绑定和分发应用程序的 Electron 工具会自动为你处理
{
    "config": {
        "forge": {
        "packagerConfig": {
            "protocols": [
            {
                "name": "Electron Fiddle",
                "schemes": ["electron-fiddle"]
            }
            ]
        },
        "makers": [
            {
            "name": "@electron-forge/maker-deb",
            "config": {
                "mimeType": ["x-scheme-handler/electron-fiddle"]
            }
            }
        ]
        }
    }
}
对于 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"

结论

Example

// 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)
})
const { contextBridge, ipcRenderer } = require('electron/renderer')

contextBridge.exposeInMainWorld('shell', {
    open: () => ipcRenderer.send('shell:open')
})
<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
    <meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'">
    <title>app.setAsDefaultProtocol 演示</title>
</head>

<body>
    <h1>App Default Protocol 演示</h1>

    <p>协议API允许我们注册自定义协议并拦截现有协议请求.</p>
    <p>这些方法允许您设置和取消设置应用程序应作为默认应用程序的协议。类似于当a
        浏览器要求作为您查看网页的默认设置.</p>

    <p>打开 <a href="https://www.electronjs.org/docs/latest/api/protocol">API完整协议文档</a> 在你的浏览器中.</p>

    -----

    <h3>示例</h3>
    <p>
        第一步:在浏览器中启动当前页面
        <button id="open-in-browser" class="js-container-target demo-toggle-button">
            单击以启动浏览器
        </button>
    </p>

    <p>
        然后:从web链接启动应用程序
        <a href="electron-fiddle://open">点击此处启动应用程序</a>
    </p>

    ----

    <p>您可以将应用程序设置为默认应用程序,以针对特定协议打开。例如,在这个演示中,我们设置了
        应用程序
        作为默认设置 <code>electron-fiddle://</code>上面的演示按钮将在默认设置下启动一个页面
        带有链接的浏览器。点击该链接,它将重新启动此应用程序。 </p>


    <h3>包装</h3>
    <p>此功能仅在您的应用程序打包后在macOS上有效。当您在中启动它时,它将不起作用
        从命令行进行开发。打包应用程序时,您需要确保macOS
        <code>plist</code>
        因为应用程序已更新以包含新的协议处理程序。如果你使用的是 <code>@electron/packager</code> 那么
        可以添加标志 <code>--extend-info</code> with a path to the <code>plist</code> you've created. The one for
        this
        app is below:</p>

    <p>
    <h5>macOS plist</h5>
    <pre><code>
    &lt;?xml version="1.0" encoding="UTF-8"?&gt;
    &lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;
            &lt;plist version="1.0"&gt;
                &lt;dict&gt;
                    &lt;key&gt;CFBundleURLTypes&lt;/key&gt;
                    &lt;array&gt;
                        &lt;dict&gt;
                            &lt;key&gt;CFBundleURLSchemes&lt;/key&gt;
                            &lt;array&gt;
                                &lt;string&gt;electron-api-demos&lt;/string&gt;
                            &lt;/array&gt;
                            &lt;key&gt;CFBundleURLName&lt;/key&gt;
                            &lt;string&gt;Electron API Demos Protocol&lt;/string&gt;
                        &lt;/dict&gt;
                    &lt;/array&gt;
                    &lt;key&gt;ElectronTeamID&lt;/key&gt;
                    &lt;string&gt;VEKTX9H2N7&lt;/string&gt;
                &lt;/dict&gt;
            &lt;/plist&gt;
        </code>
    </pre>
    <p>

        <!-- You can also require other files to run in this process -->
        <script src="./renderer.js"></script>
</body>

</html>
// This file is required by the index.html file and will
// be executed in the renderer process for that window.
// All APIs exposed by the context bridge are available here.

// Binds the buttons to the context bridge API.
document.getElementById('open-in-browser').addEventListener('click', () => {
    window.shell.open()
})

示例

示例