Electron - 如何在 linux 上创建深度链接
Posted
技术标签:
【中文标题】Electron - 如何在 linux 上创建深度链接【英文标题】:Electron - How to create deep-linking on linux 【发布时间】:2021-04-24 18:04:37 【问题描述】:我有一个 ElectronJS 项目,我在这个项目中使用了协议(深层链接)。它可以在 MacOS 和 Windows 上运行,但在 Linux 上我无法理解如何创建此协议。
我查看了 ElectronJS 文档以及网络上的问题等,但我不知道如何在 Linux 上初始化协议。正如我在 MacOS 和 Windows 上所取得的成功一样,我想要实现的只是一个与应用程序进行深度链接交互的协议。
适用于 MacOS 和 Windows 的代码:
// main.ts
// –– B ––– PROTOCOL HANDLER –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
ProtocolUtils.setDefaultProtocolClient();
// eslint-disable-next-line default-case
switch (process.platform)
case 'darwin':
ProtocolUtils.setProtocolHandlerOSX();
break;
case 'win32':
ProtocolUtils.setProtocolHandlerWin32();
break;
// –– E ––– PROTOCOL HANDLER –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
// protocol.ts
export abstract class ProtocolUtils
/**
* @description Create default protocole for call this app.
* Ex : in your browser => myapp://test
*/
public static setDefaultProtocolClient(): void
if (!app.isDefaultProtocolClient('myapp'))
// Define custom protocol handler.
// Deep linking works on packaged versions of the application!
app.setAsDefaultProtocolClient('myapp');
/**
* @description Create logic (WIN32) for open url from protocol
*/
public static setProtocolHandlerWin32(): void
// Force Single Instance Application on win32
const gotTheLock = app.requestSingleInstanceLock();
app.on('second-instance', (e: Electron.Event, argv: string[]) =>
// Someone tried to run a second instance, we should focus our window.
if (MainWindow.mainWindow)
if (MainWindow.mainWindow.isMinimized()) MainWindow.mainWindow.restore();
MainWindow.mainWindow.focus();
else
MainWindow.openMainWindow(); // Open main windows
app.whenReady().then(() =>
MainWindow.mainWindow.loadURL(this._getDeepLinkUrlForWin32(argv)); // Load URL in WebApp
);
);
if (gotTheLock)
app.whenReady().then(() =>
MainWindow.openMainWindow(); // Open main windows
MainWindow.mainWindow.loadURL(this._getDeepLinkUrlForWin32()); // Load URL in WebApp
);
else
app.quit();
/**
* @description Create logic (OSX) for open url from protocol
*/
public static setProtocolHandlerOSX(): void
app.on('open-url', (event: Electron.Event, url: string) =>
event.preventDefault();
app.whenReady().then(() =>
MainWindow.openMainWindow(); // Open main windows
MainWindow.mainWindow.loadURL(this._getUrlToLoad(url)); // Load URL in WebApp
);
);
/**
* @description Format url to load in mainWindow
*/
private static _getUrlToLoad(url: string): string
// Ex: url = myapp://deep-link/test?params1=paramValue
// Ex: Split for remove myapp:// and get deep-link/test?params1=paramValue
const urlSplitted = url.split('//');
// Generate URL to load in WebApp.
// Ex: file://path/index.html#deep-link/test?params1=paramValue
const urlToLoad = format(
pathname: Env.BUILDED_WEBAPP_INDEX_PATH,
protocol: 'file:',
slashes: true,
hash: `#$urlSplitted[1]`,
);
return urlToLoad;
/**
* @description Resolve deep link url for windows from process argv
*/
private static _getDeepLinkUrlForWin32(argv?: string[]): string
let url: string;
const newArgv: string[] = !isNil(argv) ? argv : process.argv;
// Protocol handler for win32
// argv: An array of the second instance’s (command line / deep linked) arguments
if (process.platform === 'win32')
// Get url form precess.argv
newArgv.forEach((arg) =>
if (/myapp:\/\//.test(arg))
url = arg;
);
if (!isNil(url))
return this._getUrlToLoad(url); // Load URL in WebApp
else if (!isNil(argv) && isNil(url))
throw new Error('URL is undefined');
我不担心 macOS 和 windows,但在 linux 上,即使有以下行,协议也不存在:
ProtocolUtils.setDefaultProtocolClient();
谁负责创建myapp: //
协议...
当我运行这个命令时:xdg-open myapp://deep-link/test?toto=titi
一个错误告诉我这个协议不存在
如果有人有我在 Linux 上配置的示例或者可以帮助我吗?
谢谢
【问题讨论】:
【参考方案1】:好的,我找到了解决方案!
首先,我们移除了 electron-forge 并将其替换为 electron-builder (cf doc)。
然后在阅读了大量关于 Linux 上的深层链接的文档后,文档示例:
Desktop file Specification of desktop entry Electron builder desktop file我的解决方案是:
# electron-builder.yml
appId: com.myapp.myapp
productName: myapp
directories:
output: out
linux:
icon: src/assets/icons/app/icon@256x256.png
category: Utility
mimeTypes: [x-scheme-handler/myapp] # Define MimeType
desktop: # Define desktop elem
exec: myapp %u # Define Exec
target:
- target: deb
arch:
- x64
所以我在这里用我的协议名称定义了 MimeType myapp
可以给出:
myapp://toto?foo=bar
在我的桌面文件中使用myapp %u
定义Exec,因为%u
=> 单个URL。本地文件可以作为文件:URL 或文件路径传递。(cf doc)
为了完成我的main.ts
和protocol.utils.ts
:
// main.ts
// –– B ––– PROTOCOL HANDLER –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
ProtocolUtils.setDefaultProtocolClient();
switch (process.platform)
case 'darwin':
ProtocolUtils.setProtocolHandlerOSX();
break;
case 'linux':
case 'win32':
ProtocolUtils.setProtocolHandlerWindowsLinux();
break;
default:
throw new Error('Process platform is undefined');
// –– E ––– PROTOCOL HANDLER –––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
// protocol.utils.ts
export abstract class ProtocolUtils
public static setDefaultProtocolClient(): void
if (!app.isDefaultProtocolClient('myapp'))
// Define custom protocol handler.
// Deep linking works on packaged versions of the application!
app.setAsDefaultProtocolClient('myapp');
/**
* @description Create logic (WIN32 and Linux) for open url from protocol
*/
public static setProtocolHandlerWindowsLinux(): void
// Force Single Instance Application
const gotTheLock = app.requestSingleInstanceLock();
app.on('second-instance', (e: Electron.Event, argv: string[]) =>
// Someone tried to run a second instance, we should focus our window.
if (MainWindow.mainWindow)
if (MainWindow.mainWindow.isMinimized()) MainWindow.mainWindow.restore();
MainWindow.mainWindow.focus();
else
// Open main windows
MainWindow.openMainWindow();
app.whenReady().then(() =>
MainWindow.mainWindow.loadURL(this._getDeepLinkUrl(argv));
);
);
if (gotTheLock)
app.whenReady().then(() =>
// Open main windows
MainWindow.openMainWindow();
MainWindow.mainWindow.loadURL(this._getDeepLinkUrl());
);
else
app.quit();
/**
* @description Create logic (OSX) for open url from protocol
*/
public static setProtocolHandlerOSX(): void
app.on('open-url', (event: Electron.Event, url: string) =>
event.preventDefault();
app.whenReady().then(() =>
if (!isNil(url))
// Open main windows
MainWindow.openMainWindow();
MainWindow.mainWindow.loadURL(this._getUrlToLoad(url));
else
this._logInMainWindow( s: 'URL is undefined', isError: true );
throw new Error('URL is undefined');
);
);
/**
* @description Format url to load in mainWindow
*/
private static _getUrlToLoad(url: string): string
// Ex: url = myapp://deep-link/test?params1=paramValue
// Ex: Split for remove myapp:// and get deep-link/test?params1=paramValue
const splittedUrl = url.split('//');
// Generate URL to load in WebApp.
// Ex: file://path/index.html#deep-link/test?params1=paramValue
const urlToLoad = format(
pathname: Env.BUILDED_APP_INDEX_PATH,
protocol: 'file:',
slashes: true,
hash: `#$splittedUrl[1]`,
);
return urlToLoad;
/**
* @description Resolve deep link url for Win32 or Linux from process argv
* @param argv: An array of the second instance’s (command line / deep linked) arguments
*/
private static _getDeepLinkUrl(argv?: string[]): string
let url: string;
const newArgv: string[] = !isNil(argv) ? argv : process.argv;
// Protocol handler
if (process.platform === 'win32' || process.platform === 'linux')
// Get url form precess.argv
newArgv.forEach((arg) =>
if (/myapp:\/\//.test(arg))
url = arg;
);
if (!isNil(url))
return this._getUrlToLoad(url);
else if (!isNil(argv) && isNil(url))
this._logInMainWindow( s: 'URL is undefined', isError: true );
throw new Error('URL is undefined');
这是工作:D
【讨论】:
你能分享你的 MainWindow 逻辑吗?我的意思是,您与 protocolHandler 共享主窗口的方式以上是关于Electron - 如何在 linux 上创建深度链接的主要内容,如果未能解决你的问题,请参考以下文章
如何发布适用于 Windows 或 Mac 或 Linux 系统的 Electron 应用程序?