如何从网站启动我的Electron应用程序

39
我们有一个电子加密应用程序,可以签署交易(等等)。
我们希望其他网站能够有一个按钮,打开该电子应用程序,并预填一些参数(交易信息)。
流程如下:
1. 用户在some-crypto-site.com上点击“进行交易”。 2. 电子应用程序打开并预填参数。 3. 用户在电子应用程序中点击“签署交易”。 4. 电子应用程序在幕后处理。 5. 电子应用程序关闭并向some-crypto-site.com发送消息。
这可以在运行时或安装时完成。
我尝试过的方法(Linux,Chrome):
使用此代码this gist调用app.setAsDefaultProtocolClient
app.setAsDefaultProtocolClient("my-app")

但是当我在chrome浏览器中输入my-app://foo?bar=baz后,弹出了以下窗口,点击open-xdg没有任何反应(除了关闭弹窗)

enter image description here

我调查了一下

  1. Electron 协议API似乎只处理应用程序内的协议。
  2. WebTorrent .desktop文件可能是正确的方法,只是我不确定如何操作。

也许有一种方法可以通过Electron Builder在安装时完成?

非常感谢您的帮助,我不知道该怎么做!

可能有用的资源

  1. 带有mac和window示例的github存储库
  2. 适用于linux的github评论
  3. 适用于linux的github评论2
  4. 适用于所有3个操作系统的SO答案
  5. 适用于Windows的SO答案
  6. 适用于Windows注册表的npm包
  7. 适用于Mac的SO答案
  8. 适用于Linux的SO答案
  9. 适用于Windows的Microsoft文档
  10. Windows文章
  11. 适用于Windows的github评论
  12. 适用于Mac的github评论
  13. 适用于Mac的info.plst文件
  14. 旧的Mac和Windows存储库

调用 app.setAsDefaultProtocolClient("my-app"),然后使用 my-app://foo?bar=baz 打开它会导致调用 "your/path/electron.exe my-app://foo?bar=baz"。但是 electron.exe 将其第一个参数作为应用程序路径,因此无法正常工作。 - hiitiger
@hiitiger 感谢您的评论,我不明白您的意思。您能否澄清一下? - Shining Love Star
2个回答

64

由于这可能与我在工作中所做的相关,所以我决定试一试。 不过我只在OSX上测试过!

我查看了app.setAsDefaultProtocolClient的文档,它说:

注意:在macOS上,您只能注册已添加到应用程序info.plist的协议,这些协议无法在运行时修改。但是,您可以使用简单的文本编辑器或脚本在构建时更改该文件。请参阅Apple的文档以获取详细信息。

这些协议可以在使用electron-builder打包应用程序时定义。请参见build

{
  "name": "foobar",
  "version": "1.0.0",
  "main": "main.js",
  "scripts": {
    "start": "electron .",
    "dist": "electron-builder"
  },
  "devDependencies": {
    "electron": "^3.0.7",
    "electron-builder": "^20.38.2"
  },
  "dependencies": {},
  "build": {
    "appId": "foobar.id",
    "mac": {
      "category": "foo.bar.category"
    },
    "protocols": {
      "name": "foobar-protocol",
      "schemes": [
        "foobar"
      ]
    }
  }
}

在你的主线程中:

const {app, BrowserWindow} = require('electron');

let mainWindow;

function createWindow () {
  mainWindow = new BrowserWindow({width: 800, height: 600})
  mainWindow.loadFile('index.html');
}

app.on('ready', createWindow);

var link;

// This will catch clicks on links such as <a href="foobar://abc=1">open in foobar</a>
app.on('open-url', function (event, data) {
  event.preventDefault();
  link = data;
});

app.setAsDefaultProtocolClient('foobar');

// Export so you can access it from the renderer thread
module.exports.getLink = () => link;

在您的渲染线程中:

请注意使用remote API来访问主线程中导出的getLink函数。

<!DOCTYPE html>
<html>
  <body>
    <p>Received this data <input id="data"/></p>
    <script>
      const {getLink} = require('electron').remote.require('./main.js');
      document.querySelector('#data').value = getLink();
    </script>
  </body>
</html>

示例

<a href="foobar://abc=1">open in foobar</a>

enter image description here

这还允许您从命令行启动:

open "foobar://xyz=1"

enter image description here

如何回到原始调用者?

我想当您启动应用程序时,可以在其中包含调用者URL:

<a href="foobar://abc=1&caller=example.com”>open in foobar</a>

当你的Electron应用程序处理完数据后,它只需简单地ping回那个URL。
致谢
我的大部分发现都基于:

1
太棒了,我会尽快研究一下!这在开发中是否有效,还是您必须制作安装程序并将其安装到本地计算机上才能使其正常工作?再次感谢! - Shining Love Star
我实际上还没有尝试过。这确实是针对一个打包和安装的应用程序进行测试的。 - customcommander
在Linux上,我尝试使用一个压缩的应用程序包,但它无法工作。目前我们没有为Linux使用安装程序,因此无法测试。如果我们让它工作了,我们会进行更新。 - Shining Love Star
2
请注意,open-url 事件仅适用于 Mac 系统。Windows 和 Linux 需要使用 process.argvargv 参数来遍历参数,并检查其中是否有用于启动应用程序的 URL。 - mix3d
我只是想知道您将如何调试这种应用程序? - Pragam Shrivastava
非常感谢。您用清晰的解释阐明了问题。 - Alaksandar Jesus Gene

1

与上述内容略有不同。

open-url事件在ready事件之前触发,因此您可以将其存储在变量中,并在窗口did-finish-load中使用。

let link;

let mainWindow;

function createWindow() {
    mainWindow = new BrowserWindow({
        width: 1280,
        height: 720,
        webPreferences: {
            nodeIntegration: true,
            contextIsolation: false
        }
    });
    mainWindow.openDevTools();
    mainWindow.setContentProtection(true);
    mainWindow.loadFile('index.html');
    mainWindow.webContents.on("did-finish-load", function() {
        mainWindow.webContents.send('link', link);
    });
}

app.on('ready', createWindow);

// This will catch clicks on links such as <a href="protocols://abc=1">open in foobar</a>
app.on('open-url', function(event, url) {
    link = url;
    if (mainWindow?.webContents) {
        mainWindow.webContents.send('link', link);
    }
});

app.setAsDefaultProtocolClient('protocols');

您可以像这样在渲染html中使用该值。
<!DOCTYPE html>
<html>
    <head></head>
    <body>
        <script>
            const ipc = require("electron").ipcRenderer;
            ipc.on("link", function (event, url) {
                console.log(url);
                console.log(parseQuery(decodeURI(url)));
            });
            function parseQuery(queryString) {
                queryString = queryString.substring(queryString.indexOf("://") + 3);
                var query = {};
                var pairs = (queryString[0] === "?" ? queryString.substr(1) : queryString).split("&");
                for (var i = 0; i < pairs.length; i++) {
                    var pair = pairs[i].split("=");
                    query[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || "");
                }
                return query;
            }
        </script>
    </body>
</html>

我在Windows上尝试了上述步骤,但出现错误,提示找不到Electron应用程序... 有什么建议吗? - santosh kumar
这正是我所需要的。为了解释这里的价值:open-url事件可能在主窗口初始化之前或之后到达,这取决于URL是否是应用程序启动的原因。对于“之前”的情况,我们将URL保存以便稍后在did-finish-load中处理;对于“之后”的情况,我们立即处理它(因为mainWindow不再是undefined)。 - ThatsJustCheesy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接