深度链接 (Deep Links)

    通过此教程,您会掌握如何设置您的应用以拦截并处理任意特定协议的URL的点击事件。 在本指南中,我们假定这个协议名为“”。

    首先,我们需要从electron导入所需的模块。 这些模块有助于控制应用的生命周期,或创建原生的浏览器窗口。

    其次,我们将应用注册为“electron-fiddle://”协议的处理器。

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

    现在我们定义负责创建浏览器窗口的函数,并加载应用的 index.html 文件。

    1. const createWindow = () => {
    2. // 创建浏览器窗口
    3. mainWindow = new BrowserWindow({
    4. width: 800,
    5. height: 600,
    6. webPreferences: {
    7. preload: path.join(__dirname, 'preload.js')
    8. }
    9. })
    10. mainWindow.loadFile('index.html')
    11. }

    与 MacOS 或 Linux 不同,在 Windows 下需要其他的代码。 这是因为在 Windows 中需要特别处理在同一个 Electron 实例中打开的协议的内容。 请点击 了解更多

    Windows 下代码:

    1. const gotTheLock = app.requestSingleInstanceLock()
    2. if (!gotTheLock) {
    3. app.quit()
    4. } else {
    5. app.on('second-instance', (event, commandLine, workingDirectory) => {
    6. // 用户正在尝试运行第二个实例,我们需要让焦点指向我们的窗口
    7. if (mainWindow) {
    8. if (mainWindow.isMinimized()) mainWindow.restore()
    9. mainWindow.focus()
    10. }
    11. // the commandLine is array of strings in which last element is deep link url
    12. // the url str ends with /
    13. dialog.showErrorBox('Welcome Back', `You arrived from: ${commandLine.pop().slice(0, -1)}`)
    14. })
    15. // Create mainWindow, load the rest of the app, etc...
    16. app.whenReady().then(() => {
    17. createWindow()
    18. })
    19. }

    MacOS 与 Linux 下代码:

    最后,我们还需要处理应用的关闭事件。

    1. // 在除 MacOS 的其他平台上,当所有窗口关闭后,退出当前应用。 在 MacOS 上,
    2. // 应用及其菜单栏通常会保持活跃状态,
    3. // 直到用户明确按下 Cmd + Q 退出应用
    4. app.on('window-all-closed', () => {
    5. if (process.platform !== 'darwin') app.quit()
    6. })

    打包

    在 macOS 和 Linux 上,此功能仅在应用打包后才有效。 在命令行启动的开发版中无效。 当您打包应用程序时,你需要确保应用程序的 macOS Info.plist 和 Linux .desktop 文件已更新以包含新的协议处理程序。 一些绑定和分发应用程序的 Electron 工具会自动为你处理

    如果您使用 Electron Forge,请调整 macOS 支持的 packagerConfig ,以及适当调整 Linux 制造商的 Linux 支持配置,在 Forge 配置 (请注意以下示例仅显示添加配置时所需更改的最低值)

    1. {
    2. "config": {
    3. "forge": {
    4. "packagerConfig": {
    5. "protocols": [
    6. {
    7. "name": "Electron Fiddle",
    8. "schemes": ["electron-fiddle"]
    9. }
    10. ]
    11. },
    12. "makers": [
    13. {
    14. "name": "@electron-forge/maker-deb",
    15. "config": {
    16. "mimeType": ["x-scheme-handler/electron-fiddle"]
    17. }
    18. }
    19. ]
    20. }
    21. }
    22. }

    Electron Packager

    如果您正在使用 Electron Packager 的 API,添加对协议处理程序的支持类似于 Electron Forge 的处理方式, 其他 protocols 是传递到 packager 函数的 Packager 选项的一部分。

    1. const packager = require('electron-packager')
    2. packager({
    3. // ...other options...
    4. protocols: [
    5. name: 'Electron Fiddle',
    6. schemes: ['electron-fiddle']
    7. }
    8. ]
    9. }).then(paths => console.log(`SUCCESS: Created ${paths.join(', ')}`))
    10. .catch(err => console.error(`ERROR: ${err.message}`))

    如果您使用 Electron Packager 的 CLI,请使用 --protocol--protocol-name 标志。 例如:

    启动 Electron 应用后,在浏览器内键入包含该自定义协议的 URL,如 "electron-fiddle://open" ,观察应用是否正确响应并显示一个错误提示对话框。

    docs/fiddles/system/protocol-handler/launch-app-from-URL-in-another-app (23.0.0)

    • main.js
    • preload.js
    • index.html
    • renderer.js
    1. // Modules to control application life and create native browser window
    2. const { app, BrowserWindow, ipcMain, shell, dialog } = require('electron')
    3. const path = require('path')
    4. let mainWindow;
    5. if (process.defaultApp) {
    6. if (process.argv.length >= 2) {
    7. app.setAsDefaultProtocolClient('electron-fiddle', process.execPath, [path.resolve(process.argv[1])])
    8. }
    9. } else {
    10. app.setAsDefaultProtocolClient('electron-fiddle')
    11. }
    12. const gotTheLock = app.requestSingleInstanceLock()
    13. if (!gotTheLock) {
    14. app.quit()
    15. } else {
    16. app.on('second-instance', (event, commandLine, workingDirectory) => {
    17. // Someone tried to run a second instance, we should focus our window.
    18. if (mainWindow) {
    19. if (mainWindow.isMinimized()) mainWindow.restore()
    20. mainWindow.focus()
    21. }
    22. dialog.showErrorBox('Welcome Back', `You arrived from: ${commandLine.pop().slice(0,-1)}`)
    23. })
    24. // Create mainWindow, load the rest of the app, etc...
    25. app.whenReady().then(() => {
    26. createWindow()
    27. })
    28. app.on('open-url', (event, url) => {
    29. dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`)
    30. })
    31. }
    32. function createWindow () {
    33. // Create the browser window.
    34. mainWindow = new BrowserWindow({
    35. width: 800,
    36. height: 600,
    37. webPreferences: {
    38. preload: path.join(__dirname, 'preload.js'),
    39. }
    40. })
    41. mainWindow.loadFile('index.html')
    42. }
    43. // Quit when all windows are closed, except on macOS. There, it's common
    44. // for applications and their menu bar to stay active until the user quits
    45. // explicitly with Cmd + Q.
    46. app.on('window-all-closed', function () {
    47. if (process.platform !== 'darwin') app.quit()
    48. })
    49. // Handle window controls via IPC
    50. ipcMain.on('shell:open', () => {
    51. const pageDirectory = __dirname.replace('app.asar', 'app.asar.unpacked')
    52. const pagePath = path.join('file://', pageDirectory, 'index.html')
    53. shell.openExternal(pagePath)
    54. })
    1. // All of the Node.js APIs are available in the preload process.
    2. // It has the same sandbox as a Chrome extension.
    3. const { contextBridge, ipcRenderer } = require('electron')
    4. // Set up context bridge between the renderer process and the main process
    5. contextBridge.exposeInMainWorld(
    6. 'shell',
    7. open: () => ipcRenderer.send('shell:open'),
    8. }
    9. )
    1. <!DOCTYPE html>
    2. <html>
    3. <head>
    4. <meta charset="UTF-8">
    5. <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
    6. <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
    7. <meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'">
    8. <title>app.setAsDefaultProtocol Demo</title>
    9. </head>
    10. <body>
    11. <h1>App Default Protocol Demo</h1>
    12. <p>The protocol API allows us to register a custom protocol and intercept existing protocol requests.</p>
    13. <p>These methods allow you to set and unset the protocols your app should be the default app for. Similar to when a
    14. browser asks to be your default for viewing web pages.</p>
    15. <p>Open the <a href="https://www.electronjs.org/docs/api/protocol">full protocol API documentation</a> in your
    16. browser.</p>
    17. -----
    18. <h3>Demo</h3>
    19. <p>
    20. First: Launch current page in browser
    21. <button id="open-in-browser" class="js-container-target demo-toggle-button">
    22. Click to Launch Browser
    23. </button>
    24. </p>
    25. <p>
    26. Then: Launch the app from a web link!
    27. <a href="electron-fiddle://open">Click here to launch the app</a>
    28. </p>
    29. ----
    30. <p>You can set your app as the default app to open for a specific protocol. For instance, in this demo we set this app
    31. as the default for <code>electron-fiddle://</code>. The demo button above will launch a page in your default
    32. browser with a link. Click that link and it will re-launch this app.</p>
    33. <h3>Packaging</h3>
    34. <p>This feature will only work on macOS when your app is packaged. It will not work when you're launching it in
    35. development from the command-line. When you package your app you'll need to make sure the macOS <code>plist</code>
    36. for the app is updated to include the new protocol handler. If you're using <code>electron-packager</code> then you
    37. can add the flag <code>--extend-info</code> with a path to the <code>plist</code> you've created. The one for this
    38. app is below:</p>
    39. <p>
    40. <h5>macOS plist</h5>
    41. <pre><code>
    42. &lt;?xml version="1.0" encoding="UTF-8"?&gt;
    43. &lt;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"&gt;
    44. &lt;plist version="1.0"&gt;
    45. &lt;dict&gt;
    46. &lt;key&gt;CFBundleURLTypes&lt;/key&gt;
    47. &lt;array&gt;
    48. &lt;dict&gt;
    49. &lt;key&gt;CFBundleURLSchemes&lt;/key&gt;
    50. &lt;array&gt;
    51. &lt;string&gt;electron-api-demos&lt;/string&gt;
    52. &lt;/array&gt;
    53. &lt;key&gt;CFBundleURLName&lt;/key&gt;
    54. &lt;string&gt;Electron API Demos Protocol&lt;/string&gt;
    55. &lt;/dict&gt;
    56. &lt;/array&gt;
    57. &lt;key&gt;ElectronTeamID&lt;/key&gt;
    58. &lt;string&gt;VEKTX9H2N7&lt;/string&gt;
    59. &lt;/dict&gt;
    60. &lt;/plist&gt;
    61. </code>
    62. </pre>
    63. <p>
    64. <!-- You can also require other files to run in this process -->
    65. <script src="./renderer.js"></script>
    66. </body>